Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fsum for numpy.arrays, stable summation

I have a number of multidimensional numpy.arrays with small values that I need to add up with little numerical error. For floats, there is math.fsum (with its implementation here), which has always served me well. numpy.sum isn't stable enough.

How can I get a stable summation for numpy.arrays?


Background

This is for the quadpy package. The arrays of small values are the evaluations of a function at specific points of (many) intervals, times their weights. The sum of these is an approximation of the integral of said function over the intervals.

like image 693
Nico Schlömer Avatar asked Mar 15 '17 17:03

Nico Schlömer


People also ask

How do I sum two NumPy arrays?

To add the two arrays together, we will use the numpy. add(arr1,arr2) method. In order to use this method, you have to make sure that the two arrays have the same length. If the lengths of the two arrays are​ not the same, then broadcast the size of the shorter array by adding zero's at extra indexes.

What do you get if you apply NumPy sum () to a list that contains only Boolean values?

sum receives an array of booleans as its argument, it'll sum each element (count True as 1 and False as 0) and return the outcome. for instance np. sum([True, True, False]) will output 2 :) Hope this helps.

How do you transpose a NumPy array in Python?

NumPy Matrix transpose() - Transpose of an Array in Python The transpose of a matrix is obtained by moving the rows data to the column and columns data to the rows. If we have an array of shape (X, Y) then the transpose of the array will have the shape (Y, X).


1 Answers

Alright then, I've implemented accupy which gives a few stable summation algorithms.

Here's a quick and dirty implementation of Kahan summation for numpy arrays. Notice, however, that it is not not very accurate for ill-conditioned sums.

def kahan_sum(a, axis=0):
    '''Kahan summation of the numpy array along an axis.
    '''
    s = numpy.zeros(a.shape[:axis] + a.shape[axis+1:])
    c = numpy.zeros(s.shape)
    for i in range(a.shape[axis]):
        # https://stackoverflow.com/a/42817610/353337
        y = a[(slice(None),) * axis + (i,)] - c
        t = s + y
        c = (t - s) - y
        s = t.copy()
    return s

It does the job, but it's slow because it's Python-looping over the axis-th dimension.

like image 60
Nico Schlömer Avatar answered Oct 08 '22 16:10

Nico Schlömer