1

I have some problems with the efficiency of my code. Basically my code works like this:

a = zeros(1,50000);
for n = 1:50000
    a(n) = 10.*n - 5;
end
sum(a);

What is the fastest way to solve the sum of all the elements of this matrix?

Matt
  • 12,848
  • 2
  • 31
  • 53
anonymous
  • 115
  • 6
  • What is the performance issue in this small piece of code? There is no faster way than `sum` **to calculate the sum** as far as I know. However, you can generate the `a`-matrix easier like this: `n = 1:50000; a = 10*n - 5;` – Matt Apr 06 '16 at 09:30
  • (1) oops. my bad. just edited the post. (2) i was just wondering if there was a faster way to do the sum. :) – anonymous Apr 06 '16 at 09:33

1 Answers1

3

first you want to remove your for loop by making it a vector multiplication:

tic
a = zeros(1,50000);
b = [1:50000];
   a = 10.*b-5;
result = sum(a);
toc
Elapsed time is 0.008504 seconds.

An alternative way is to simplify your operation, you are multiplying 1 to 50000 by 10 and subtracting 5 then taking the sum (which is a single number), which is equivalent to:

tic
result = sum(1:50000)*10 - 5*50000;
toc
Elapsed time is 0.003851 seconds.

or if you are really into Math (this is a pure mathematical expression approach) :

tic
result = (1+50000)*(50000/2)*10 - 5*50000;
toc
Elapsed time is 0.003702 seconds.

and as you can see, a little math can do greater good than pure efficient programming, and actually, loop is not always slow, in your case, the loop is actually faster than the vectorized method:

tic
a = zeros(1,50000);
  for n = 1:50000
     a(n)=10.*n-5;
  end
sum(a);
toc
Elapsed time is 0.006431 seconds.

Timing

Let's do some timing and see the results. The function to run it yourself is provided at the bottom. The approximate execution time execTime is in seconds and the percentage of improvement impPercentage in %.

Results

  • R2016a on OSX 10.11.4

                   execTime     impPercentage
                  __________    _____________
    loop          0.00059336         0       
    vectorized    0.00014494    75.574       
    adiel         0.00010468    82.359       
    math          9.3659e-08    99.984       
    

Code

The following function can be used to generate the output. Note that it requires minimum R2013b to be able to use the built-in timeit-function and table.

function timings
%feature('accel','on')      %// commented out because it's undocumented
cycleCount = 100;
execTime = zeros(4,cycleCount);
names = {'loop';'vectorized';'adiel';'math'};
w = warning;
warning('off','MATLAB:timeit:HighOverhead');
for k = 1:cycleCount
    execTime(1,k) = timeit(@()loop,1);
    execTime(2,k) = timeit(@()vectorized,1);
    execTime(3,k) = timeit(@()adiel,1);
    execTime(4,k) = timeit(@()math,1);
end
warning(w);
execTime = min(execTime,[],2);
impPercentage = (1 - execTime/max(execTime)) * 100;
table(execTime,impPercentage,'RowNames',names)


function result = loop
a = zeros(1,50000);
for n = 1:50000
    a(n) = 10.*n - 5;
end
result = sum(a);

function result = vectorized
b = 1:50000;
a = 10.*b - 5;
result = sum(a);

function result = adiel
result = sum(1:50000)*10 - 5*50000;

function result = math
result = (1+50000)*(50000/2)*10 - 5*50000;
GameOfThrows
  • 4,510
  • 2
  • 27
  • 44
  • These timings are not representative since you only executed it once. Do it 10'000 or more times to see that the vectorized solution is more than 3 times faster. – Matt Apr 06 '16 at 10:03
  • Why all this...? Simply `a=10*(1:50000)-5` is much faster than any of those options. – Adiel Apr 06 '16 at 10:07
  • @Matt nope, I am getting similar performance results, do you want to share your code/answer so I can try to recreate it? – GameOfThrows Apr 06 '16 at 10:09
  • @Adiel nope again, you are missing the sum of the matrix part, and how can this method be faster than my second and third method? – GameOfThrows Apr 06 '16 at 10:09
  • @Adiel in fact my third solution is over 50 times faster than your solution. Please share your code/timer result to compare. – GameOfThrows Apr 06 '16 at 10:12
  • Ok, checked again. Your second option is almost the same as mine. But still, the first and the third are completely unnecessary. – Adiel Apr 06 '16 at 10:13
  • @Adiel The first one is a standard vectorized version to look just like the OP's code, the third is actually much faster than your code as it involves 2 additions and 4 multiplications. – GameOfThrows Apr 06 '16 at 10:14
  • So... very interesting. I ran your codes as you wrote it, in three lines: `tic`, `result...`, `toc`. But, if I run it in the same one line (as I run mine), it suddenly becomes hundreds of time faster... This worth a separate question... Indeed, your third is the faster. – Adiel Apr 06 '16 at 10:19
  • @Adiel the third one uses only pure math expressions, I do not think any method can be faster than this; I iterated 10000 times just to show how much faster the third method really is. – GameOfThrows Apr 06 '16 at 10:24
  • Simplest solution: `result = 12500000000;` ;) – Hugh Nolan Apr 06 '16 at 11:11
  • @GameOfThrows I get 1.757s and 6.628s with your 10'000-times script. Something seems strange here, but I can't see what it is. Check [this](http://i.stack.imgur.com/EYjSr.png). – Matt Apr 06 '16 at 11:31
  • 1
    @Matt this question has been edited to a community wiki, maybe someone else could explain/edit the different results we are getting. – GameOfThrows Apr 06 '16 at 11:53
  • @Matt I haven't seen anyone mention versions yet. There has been a huge overhaul of the MATLAB execution engine recently, and basic computations like these might have drastically different relative performance. That, and `tic/toc` is not a precise way to measure performance. All code should be put in full named functions to let the JIT compiler do its job, `tic/toc` needs to be warmed up (but using `timeit` is even better where available), and results should not be compared between major MATLAB versions. – Andras Deak -- Слава Україні Apr 06 '16 at 17:35
  • @AndrasDeak This is a really good point to consider... `timeit` seems like handy way to measure the execution time of a function since it runs it multiple times internally and therefore provides a more accurate result. [Here](http://ch.mathworks.com/help/matlab/matlab_prog/measure-performance-of-your-program.html) are some more tips if you didn't know this page of the documentation. – Matt Apr 06 '16 at 18:34
  • 1
    Thank you for adding the timing performance @Matt, I had the version 2010b when I was testing this. – GameOfThrows Apr 07 '16 at 08:10