Optimising a simple mathematical calculation over list

Question:

I have a script where I am computing:

def sumsquared(arr):
    sum = 0
    idx = 0
    len = arr.__len__()
    while idx < (len - 1):
            sum = sum + (arr[idx] * arr[idx]) + (arr[idx+1] * arr[idx+1])
            idx = idx + 2

    return sum

The above function is called in a loop which populates two lists and calls this function twice: First time with a list of len ~ 1024 items and second time with len ~ 44100 items. The loop itself can run anywhere from 100 to 100000 times depending upon the input.

For a small sized input, cProfile based profiling informs me:

ncalls  tottime  percall  cumtime  percall  filename:lineno(function)
---------------------------------------------------------------------
 2560   12.065   0.005    12.065    0.005    beat.py:8(sumsquared)

which is about 95% of the total running time for the script. Is there some way I can get some speed up on the function?

Asked By: WeaklyTyped

||

Answers:

Your function is very strange. All it does is compute the sum of the squares of the elements, except that it throws away the last element if there are an odd number of elements. You add them two at a time for some reason, but that doesn’t affect the end result.

To make it faster, you could use numpy instead of writing your own function.

>>> x = np.array([1, 2, 3, 4, 5])
>>> sumsquared(x)
30
>>> (x[:2*(len(x)//2)]**2).sum()
30

In general, if you have lists of thousands of numbers, using numpy arrays instead is likely to bring a major performance gain.

Answered By: BrenBarn

This looks like a job for the itertools module:

def sumsquared(arr):
    s = sum(itertools.imap(operator.mul, arr, arr))
    return s - arr[-1] ** 2 if len(arr) & 1 else s

The use of sum, operator, and itertools will eliminate almost all of the pure python overhead.

Also, sum has been optimized to run at nearly C speed when the inputs are ints, floats, or some mix of the two. It is able to accumulate running totals without creating pure python objects for every intermediate subtotal.

Credit: Robert King for the idea of subtracting the final square when necessary.

One other note, if you’re interested in obtaining high accuracy (i.e. minimizing loss of precision), consider using math.fsum instead of sum.

Answered By: Raymond Hettinger
sum([i**2 for i in arr]) - (arr[-1]**2 if len(arr) % 2 else 0)
Answered By: Rusty Rob

This is the fastest I can find

from itertools import imap
from operator import mul
def sumsquared(arr):
    return sum(imap(mul, arr, arr))
Answered By: John La Rooy
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.