2

I am trying to improve the speed of script I am trying to run.

Here is the code: (my machine = 4 core win 7)

clear y;
n=100;
x=linspace(0,1,n);
% no y pre-allocation using zeros
start_time=tic;

for k=1:n,
    y(k) =  (1-(3/5)*x(k)+(3/20)*x(k)^2 -(x(k)^3/60)) / (1+(2/5)*x(k)-(1/20)*x(k)^2);
end

elapsed_time1 = toc(start_time);
fprintf('Computational time for serialized solution: %f\n',elapsed_time1);

Above code gives 0.013654 elapsed time.

On the other hand, I was tried to use pre-allocation by adding y = zeros(1,n); in the above code where the comment is but the running time is similar around ~0.01. Any ideas why? I was told it would improve by a factor of 2. Am I missing something?

Lastly is there any type of vectorization in Matlab that will allow me to forget about the for loop in the above code?

Thanks,

user1234440
  • 22,521
  • 18
  • 61
  • 103

3 Answers3

3

In your code: try with n=10000 and you'll see more of a difference (a factor of almost 10 on my machine).

These things related with allocation are most noticeable when the size of your variable is large. In that case it's more difficult for Matlab to dynamically allocate memory for that variable.


To reduce the number of operations: do it vectorized, and reuse intermediate results to avoid powers:

y = (1 + x.*(-3/5 + x.*(3/20 - x/60))) ./ (1 + x.*(2/5 - x/20));

Benchmarking:

With n=100:

Parag's / venergiac's solution:

>> tic
for count = 1:100
y=(1-(3/5)*x+(3/20)*x.^2 -(x.^3/60))./(1+(2/5)*x-(1/20)*x.^2);
end
toc
Elapsed time is 0.010769 seconds.

My solution:

>> tic
for count = 1:100
y = (1 + x.*(-3/5 + x.*(3/20 - x/60))) ./ (1 + x.*(2/5 - x/20));
end
toc
Elapsed time is 0.006186 seconds.
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • Really? I don't see more than a 2X speed improvement event with n=1000000. – grantnz Feb 04 '14 at 22:07
  • 1
    @Parag Thanks! I reused the trick from [here](http://stackoverflow.com/questions/18993590/efficient-way-to-take-powers-of-a-vector), actually – Luis Mendo Feb 04 '14 at 22:24
  • @LuisMendo MATLAB is an interpreter, but what do you think, is there any language (or software) which will identify this automatically, do optimization while compiling so that user necessarily does not have to know these tricks? – Autonomous Feb 04 '14 at 22:26
  • @Parag I really don't know... It shouldn't be too hard for the compiler. Anyway, it's not hard for the programmer, either (and it's funny!), to think in those terms in order to reduce operations :-) – Luis Mendo Feb 04 '14 at 22:33
  • 1
    @LuisMendo Its not hard, it doesn't strike quickly. You won't realize, you have 14K reputation... just kidding... – Autonomous Feb 04 '14 at 22:35
2

You don't need a for loop. Replace the for loop with the following and MATLAB will handle it.

y=(1-(3/5)*x+(3/20)*x.^2 -(x.^3/60))./(1+(2/5)*x-(1/20)*x.^2);

This may give a computational advantage when vectors become larger in size. Smaller size is the reason why you cannot see the effect of pre-allocation. Read this page for additional tips on how to improve the performance.

Edit: I observed that at larger sizes, n>=10^6, I am getting a constant performance improvement when I try the following:

x=0:1/n:1;

instead of using linspace. At n=10^7, I gain 0.05 seconds (0.03 vs 0.08) by NOT using linspace.

Autonomous
  • 8,935
  • 1
  • 38
  • 77
  • 1
    The number of operations (and elapsed time) can be reduces by reusing intermediate results to avoid powers; see my answer. – Luis Mendo Feb 04 '14 at 22:13
  • @LuisMendo I did a test with your and mine code for n=100000 and I got a 10x improvement (1.132 vs 0.155). It is really surprising to me that manually factorizing makes so much of a difference. – Autonomous Feb 04 '14 at 22:22
1

try operation element per element (.*, .^)

clear y;
n=50000;
x=linspace(0,1,n);
% no y pre-allocation using zeros
start_time=tic;

for k=1:n,
    y(k) =  (1-(3/5)*x(k)+(3/20)*x(k)^2 -(x(k)^3/60)) / (1+(2/5)*x(k)-(1/20)*x(k)^2);
end

elapsed_time1 = toc(start_time);
fprintf('Computational time for serialized solution: %f\n',elapsed_time1);

start_time=tic;
y =  (1-(3/5)*x+(3/20)*x.^2 -(x.^3/60)) / (1+(2/5)*x-(1/20)*x.^2);

elapsed_time1 = toc(start_time);
fprintf('Computational time for product solution: %f\n',elapsed_time1);

my data

Computational time for serialized solution: 2.578290

Computational time for serialized solution: 0.010060

Community
  • 1
  • 1
venergiac
  • 7,469
  • 2
  • 48
  • 70