Skip to content

Euler, Euler, Euler, Oi, Oi, Oi!

November 26, 2009

The Last of the Careless Men blog kindly referred to my Euler blog post from last week.

The blog post brought to my attention the Euler Benchmark Suite. To quote from the Readme:

The Euler Benchmark Suite aims at comparing language speeds for the Euler

So I was curious to see what this version of the Euler 4 in Perl5 looked like.

use strict; use warnings;
my $max = 0;
for my $a ( 100..999 ){
    for my $b ( $a..999 ){
        my $product = $a * $b;
        $max = $product if $product > $max
                       and $product eq reverse $product;
print "$max\n";

At first glance this doesn’t look as “elegant” as the functional code I posted last week.

However remember the above code was optimised for speed! It comes it at 3.5 times faster than even this slightly more optimised version of last weeks functional code below, which now comes it at around 0.48s here:

say max 
    grep { $_ eq reverse $_ } 
    map {
        my $x = $_;
        map { $x * $_ } $x .. 1000;
    } 100..1000;


Another thing of interest from the blog post was the Perl6 example. Like with Ruby example its definitely easier to grok things going in a chain from left to right, ie. just like how we read english text.

autobox to the rescue!

use autobox::Core;

[1..1000]->map( sub{ my $x = $_; map { $x * $_ } $x..1000 } )->grep( sub{ $_ eq reverse $_ } )->max->say;

Not bad. And comes in at respectabe average of 1.25s. However having that extra map within the map method is not too elegant.

Luckily autobox is extensible! So lets add a Cartesian Product method to autobox:

use autobox::Core;

sub autobox::Core::ARRAY::product {
    my $a = shift;
    my @c = map { [ $_ ] } @$a;
    for my $b (@_) {
        @c = map { my $x = $_; map { [ $x, @$_ ] } @c } @$b;   
    return \@c;

[1..1000]->product( [1..1000] )->map( sub{ $_->[0] * $_->[1] } )->grep( sub{ $_ eq reverse $_ } )->max->say;

Now thats really nice. Now if future versions of Perl can provide a mechanism to allow for blocks (ie. anonymous subs) to passed more seamlessly, say like

[1..1000]->product( [1..1000] )->map(){ $_->[0] * $_->[1] }->grep(){ $_ eq reverse $_ }->max->say;

# or even

[1..1000]->product( [1..1000] )->map{ $_->[0] * $_->[1] }->grep{ $_ eq reverse $_ }->max->say;

Then we’re really cooking!


This post is in memory of Colin. My Father-in-law and a fellow blogger who suddenly and unexpectedly passed away yesterday. RIP

No comments yet

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: