From: Quentin CAUDRON on
Hi everyone,

As an example for an introductory computing class I'm giving, I've written some code to calculate pi using the "darts" idea ( Monte Carlo derivative ).

I've written the following function, which runs in about eight to nine seconds on my system :

function [mypi, time] = pi_approx(iterations)

% Start the clock
tic;

counter = 0;

for i = 1 : iterations
x(1) = rand;
x(2) = rand;

if norm(x) <= 1
counter = counter + 1;
end
end

mypi = counter * 4 / iterations;

time = toc;



However, when I replace the vector variable x with two doubles, x and y, and replace the norm() function with the square root of the sum of x^2 and y^2, the code ( below ) runs about two seconds.

function [mypi, time] = pi_approx2(iterations)

% Start the clock
tic;

counter = 0;

for i = 1 : iterations
x = rand;
y = rand;

if sqrt(x^2 + y^2) <= 1
counter = counter + 1;
end
end

mypi = counter * 4 / iterations;

time = toc;




Any ideas as to why this is so much faster ?

Thank you,
Quentin
From: Sebastiaan on
"Quentin CAUDRON" <q.caudron(a)warwick.ac.uk> wrote in message <hafblo$fkc$1(a)fred.mathworks.com>...
> Hi everyone,
>
> As an example for an introductory computing class I'm giving, I've written some code to calculate pi using the "darts" idea ( Monte Carlo derivative ).
>
> I've written the following function, which runs in about eight to nine seconds on my system :
>
> function [mypi, time] = pi_approx(iterations)
>
> % Start the clock
> tic;
>
> counter = 0;
>
> for i = 1 : iterations
> x(1) = rand;
> x(2) = rand;
>
> if norm(x) <= 1
> counter = counter + 1;
> end
> end
>
> mypi = counter * 4 / iterations;
>
> time = toc;
>
>
>
> However, when I replace the vector variable x with two doubles, x and y, and replace the norm() function with the square root of the sum of x^2 and y^2, the code ( below ) runs about two seconds.
>
> function [mypi, time] = pi_approx2(iterations)
>
> % Start the clock
> tic;
>
> counter = 0;
>
> for i = 1 : iterations
> x = rand;
> y = rand;
>
> if sqrt(x^2 + y^2) <= 1
> counter = counter + 1;
> end
> end
>
> mypi = counter * 4 / iterations;
>
> time = toc;
>
>
>
>
> Any ideas as to why this is so much faster ?
>
Function overhead. Calling the 'norm' function in stead of 'sqrt' increases time. Some timings from me:

1) Your 1st approach: x(1), x(2), norm
6.77 secs

2) Your 2nd approach: x, y, sqrt
1.98 secs

3) Use x(1) = rand, x(2) = rand, AND sqrt(x(1)^2+x(2)^2)
1.90 secs

So, try to minimize the number of function calls in a loop. Note that you are also calling the rand function in every iteration. Call this once:

4)
x = rand(iterations, 2);
for i = 1 : iterations
if sqrt(x(i,1)^2+x(i,2)^2) <= 1
counter = counter + 1;
end
end
0.87 secs

Note that for a large number of iterations the memory might become a burden, so you might want to split the randomizer in blocks, e.g.
N = 5;
for j=1:N
x = rand(iterations/N, 2);
for i=1:iterations/N
....

Now that I am busy with your code, let's do something more challenging by vectorizing it completely ;)
5)
x = rand(iterations, 2);
y = sqrt(x(:,1).^2+x(:,2).^2);
counter = sum(y<=1);
0.68 secs

6) Or not use y:
x = rand(iterations, 2);
counter = sum(sqrt(x(:,1).^2+x(:,2).^2)<=1);
0.49 secs

7) To avoid the problem of allocation memory for a large number of iterations, split it up in blocks:
block = 1e5;
counter = 0;
for i=1:ceil(iterations/block)
% Capture remainder of blocks
if block*i<=iterations
NoIter = block;
else
NoIter = mod(iterations, block);
end

x = rand(NoIter, 2);
counter = counter + sum(sqrt(x(:,1).^2+x(:,2).^2)<=1);
end


Sorry if I took away the fun of the excersise :s

Sebastiaan

> Thank you,
> Quentin
From: John D'Errico on
"Quentin CAUDRON" <q.caudron(a)warwick.ac.uk> wrote in message <hafblo$fkc$1(a)fred.mathworks.com>...
> Hi everyone,
>
> As an example for an introductory computing class I'm giving, I've written some code to calculate pi using the "darts" idea ( Monte Carlo derivative ).
>
> I've written the following function, which runs in about eight to nine seconds on my system :
>
> function [mypi, time] = pi_approx(iterations)
>
> % Start the clock
> tic;
>
> counter = 0;
>
> for i = 1 : iterations
> x(1) = rand;
> x(2) = rand;
>
> if norm(x) <= 1
> counter = counter + 1;
> end
> end
>
> mypi = counter * 4 / iterations;
>
> time = toc;
>

First of all, use the capabilities of MATLAB when
you teach it!!!!!!! Don't assign the elements of x
independently, as distinct statements. Teach your
students to work with vectors of elements from
the very beginning! So a looped version might
look like this (after I corrected your code, because
you used the wrong direction for the inequality.)

tic;
counter = 0;
for iter = 1 : iterations
x = rand(1,2);
counter = counter + (norm(x) <= 1);
end
mypi = counter * 4 / iterations;
time = toc;

Even better, I might try this:

tic;
counter = 0;
for i = 1 : iterations
counter = counter + (abs(rand + j*rand) <= 1);
end
mypi = counter * 4 / iterations;
time = toc;

But really, I would NEVER do it using a loop at all!
The MATLAB way might be like this:

tic
count = sum(abs(rand(1,iterations) + j*rand(1,iterations)) <= 1);
mypi = count*4/iterations;
toc

Or, if you prefer, use sqrt.

tic
count = sum(sqrt(rand(1,iterations).^2 + rand(1,iterations).^2) <= 1);
mypi = count*4/iterations;
toc

Note that for 10000 iterations, either of these methods
took a fraction of the time required for your loop.

Use the capability of MATLAB. Don't write MATLAB as
if you are writing C or basic.

John
From: Sebastiaan on
More is possible: remove the sqrt call: sqrt(x)<=1 is the same as x<=1:

0.35 secs
counter = counter + sum((x(:,1).^2+x(:,2).^2)<=1);

Not bad, coming from 6.77 to 0.35 secs: speedup of 20.
From: Rune Allnor on
On 6 Okt, 14:50, "John D'Errico" <woodch...(a)rochester.rr.com> wrote:

> First of all, use the capabilities of MATLAB when
> you teach it!!!!!!!

Or rather, decide if you want to teach programming
or if you want to teach matlab.

The first approach about separating the algorithm
into small, easily understood, easily tested separate
functions is what is considered 'best practices' when
programming the compiled languages: The focus is on
the human reader and maintainer of the code, the
compiler is left to optimize away function overheads
and so on.

Matlab is not a compiled language, and thus has a
lot of inherent bottlenecks.

Just about anything that makes matlab go fast, breaks
with what is otherwise considered 'best practice'
programming. Which is a very good reason for *not*
teaching 'the capacities of matlab' for newbie
programmers.

Rune