Keep It Simple, Stupid PerlMonks

Re^4: Monte Carlo - Coin Toss

by repellent (Priest)
 on Mar 13, 2011 at 04:31 UTC ( #892898=note: print w/replies, xml ) Need Help??

in reply to Re^3: Monte Carlo - Coin Toss
in thread Monte Carlo - Coin Toss

Here's a slightly speedier alternative to get Pascal's triangle row for the number of tosses:
```sub pascal_tri_row {
my \$r = shift;
return () if \$r < 0;

my @row = (1) x (\$r + 1);

for my \$i (1 .. \$r - 1)
{
\$row[\$_] += \$row[\$_ - 1]
for reverse 1 .. \$i;
}
return @row;
}

sub triangle {
my \$numTosses = shift;

my @triangle = (0, 1, 0);
for (1 .. \$numTosses) {
my @newTriangle=(0);
push @newTriangle, \$triangle[\$_]+\$triangle[\$_+1] for 0 .. \$#tr
+iangle-1;
push @newTriangle, 0;
@triangle = @newTriangle;
}

return @triangle;
}

use Benchmark qw(cmpthese);

cmpthese -1, {
robo_tri => sub { triangle(32) },
repel_tri => sub { 0, pascal_tri_row(32), 0 }, # 0's to match tria
+ngle()'s return
};

__END__

Rate  robo_tri repel_tri
robo_tri  1128/s        --      -38%
repel_tri 1811/s       60%        --

Replies are listed 'Best First'.
Re^5: Monte Carlo - Coin Toss
by roboticus (Chancellor) on Mar 13, 2011 at 05:45 UTC

Sweet! So of course I had to take another look:

```sub pascal_tri_row {
my \$r = shift;
return () if \$r < 0;

my @row = (1) x (\$r + 1);

for my \$i (1 .. \$r - 1)
{
\$row[\$_] += \$row[\$_ - 1]
for reverse 1 .. \$i;
}
return @row;
}

sub robo_2 {
my \$row = shift;
my @cols = (1);
++\$row;
\$cols[\$_] = \$cols[\$_-1] * (\$row-\$_)/\$_ for 1 .. \$row-1;
return @cols;
}

sub triangle {
my \$numTosses = shift;

my @triangle = (0, 1, 0);
for (1 .. \$numTosses) {
my @newTriangle=(0);
push @newTriangle, \$triangle[\$_]+\$triangle[\$_+1] for 0 .. \$#tr
+iangle-1;
push @newTriangle, 0;
@triangle = @newTriangle;
}

return @triangle[1..\$#triangle-1];
}

use Benchmark qw(cmpthese);

print "robo_1: ", join(" ",triangle(8)), "\n";
print "repel1: ", join(" ",pascal_tri_row(8)), "\n";
print "robo_2: ", join(" ",robo_2(8)), "\n";

cmpthese -1, {
robo_tri  => sub { triangle(32) },
repel_tri => sub { pascal_tri_row(32) },
robo_2    => sub { robo_2(32) },
};

First I put in a trace so I could be sure I wasn't generating useless values. Next, I couldn't bear the zeroes you had to add to your function to match my original return value. They were just sentinel values to simplify the calculation, anyway. So I fixed the original to return only the values of interest. Finally, I had to squeeze a little more speed out of it:

```\$ perl 892898.pl
robo_1: 1 8 28 56 70 56 28 8 1
repel1: 1 8 28 56 70 56 28 8 1
robo_2: 1 8 28 56 70 56 28 8 1
Rate  robo_tri repel_tri    robo_2
robo_tri   2196/s        --      -42%      -93%
repel_tri  3775/s       72%        --      -88%
robo_2    31946/s     1355%      746%        --

You should've read a bit further down in the wikipedia article you linked. It had a much better algorithm for calculating the coefficients of any row. It saved a nested loop.

;^)

...roboticus

When your only tool is a hammer, all problems look like your thumb.

Wonderful! That is the one. Thanks, roboticus.

Create A New User
Node Status?
node history
Node Type: note [id://892898]
help
Chatterbox?
 [choroba]: It works about 2.5 times faster than the original sort [Corion]: choroba: Well, it should be faster since it exploits that it only has to sort much smaller lists :) [Corion]: Also, it outputs (partial) results much earlier, which is nice too :) [choroba]: I hope it's ok , there's just no reaction from the OP

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2018-02-22 08:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
When it is dark outside I am happiest to see ...

Results (289 votes). Check out past polls.

Notices?