For 1-D numpy arrays, this two expressions should yield the same result (theorically):
(a*b).sum()/a.sum()
dot(a, b)/a.sum()
The latter uses dot()
and is faster. But which one is more accurate? Why?
Some context follows.
I wanted to compute the weighted variance of a sample using numpy.
I found the dot()
expression in another answer, with a comment stating that it should be more accurate. However no explanation is given there.
Numpy dot is one of the routines that calls the BLAS library that you link on compile (or builds its own). The importance of this is the BLAS library can make use of Multiply–accumulate operations (usually Fused-Multiply Add) which limit the number of roundings that the computation performs.
Take the following:
Not exact, but close enough.
The
np.dot(a, a)
will be the more accurate of the two as it use approximately half the number of floating point roundings that the naive(a*a).sum()
does.A book by Nvidia has the following example for 4 digits of precision.
rn
stands for 4 round to the nearest 4 digits:Of course floating point numbers are not rounded to the 16th decimal place in base 10, but you get the idea.
Placing
np.dot(a,a)
in the above notation with some additional pseudo code:While
(a*a).sum()
is:From this its easy to see that the number is rounded twice as many times using
(a*a).sum()
compared tonp.dot(a,a)
. These small differences summed can change the answer minutely. Additional exmaples can be found here.