-
-
Save scruss/f7af59d59efd6af2c7964cb8f771c828 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl | |
# collatz-memo.pl | |
# run time: appx 7 s | |
# output: max: 8400511 steps: 685 | |
use v5.20; | |
use strict; | |
use warnings; | |
my ( $maxsteps, $maxval, $n, $steps, $x ) = qw/0 0 0 0 1/; | |
my @s; | |
$s[$x] = 0; | |
foreach $x ( 1 .. 10000000 ) { | |
$steps = 0; | |
$n = $x; | |
while ( ( $n > 1 ) && ( $n >= $x ) ) { | |
$n = ( $n & 1 ) ? 3 * $n + 1 : $n >> 1; | |
$steps++; | |
} | |
$steps += $s[$n]; | |
$s[$x] = $steps; | |
( $maxsteps, $maxval ) = ( $steps, $x ) if ( $steps > $maxsteps ); | |
} | |
say 'max: ', $maxval, ' steps: ', $maxsteps; | |
exit; |
#!/usr/bin/env raku | |
# collatz-memo - uses over 10 GB and fails to complete in 5+ minutes | |
# raku version v2022.07 | |
# equivalent Perl5 completes in 7 s and minimal memory | |
my ( $maxsteps, $maxval, $n, $steps, $x ) = qw/0 0 0 0 1/; | |
my @s; | |
@s[$x] = 0; | |
# Perl 5 used | |
# foreach $x ( 1 .. 10000000 ) { | |
loop ($x=1; $x <= 10000000; $x++) { | |
$steps = 0; | |
$n = $x; | |
while ( ( $n > 1 ) && ( $n >= $x ) ) { | |
$n = ( $n & 1 ) ?? 3 * $n + 1 !! $n +> 1; | |
$steps++; | |
} | |
$steps += @s[$n]; | |
@s[$x] = $steps; | |
( $maxsteps, $maxval ) = ( $steps, $x ) if ( $steps > $maxsteps ); | |
} | |
say 'max: ', $maxval, ' steps: ', $maxsteps; | |
exit; |
You're using $n & 1, when you should have been using $n +& 1
Ah, thanks. The interpreter didn't complain and these language changes are non-obvious
It didn't complain because it was syntacticly valid code. Semantically pretty non-sensical in that context, but there you go.
Oddly enough, you did notice that the bit-shift right operator is +>
. Anyways, all of those bitty operators start with a +
, so at least that is consistent. So the bitwise OR is +|
.
But yeah, I guess you could call &
a false friend coming from Perl. I'll give you that :-)
I'm pretty amazed that I managed to pick up the +>
thing from Perl to Raku guide - in a nutshell: I think the interpreter complained so I read up on it. It's a shame that Raku doesn't switch from int to bigints automatically like Python does: it's a huge speed increase
Your Raku code is incorrect.
You're using
$n & 1
, when you should have been using$n +& 1
. The former creates aJunction
in which all of the elements must be true, which in this case would be false only if$n
were zero. After correcting this, your Raku version runs in about 35 seconds:whereas your Perl version runs in just over 6 seconds:
So Perl comes out 5.5x faster. Still a sizeable amount. However, Raku uses bigints by default, and Perl uses native ints by default. If we change the Raku program to use native integers (and some other Raku-fication such as removing unnecessary parens) becomes:
And this runs at just over 8 seconds:
which makes Perl only 1.3x as fast (30% faster) than Raku for this job.