I've been playing with some Perl programs to calculate excellent numbers. Although the runtimes for my solutions were acceptable, I thought a different language, especially one designed for numeric stuff, might be faster. A friend suggested Julia, but the performance I'm seeing is so bad I must be doing something wrong. I've looked through the Performance Tips and don't see what I should improve:
digits = int( ARGS[1] )
const k = div( digits, 2 )
for a = ( 10 ^ (k - 1) ) : ( 10 ^ (k) - 1 )
front = a * (10 ^ k + a)
root = floor( front ^ 0.5 )
for b = ( root - 1 ): ( root + 1 )
back = b * (b - 1);
if back > front
break
end
if log(10,b) > k
continue
end
if front == back
@printf "%d%d\n" a b
end
end
end
I have an equivalent C program that's an order of magnitude faster instead of the factor of 2 noted on the Julia page (although most of the Stackoverflow questions about Julia's speed seem to point out flawed benchmarks from that page):
And the non-optimized pure Perl I wrote takes half as long:
use v5.20;
my $digits = $ARGV[0] // 2;
die "Number of digits must be even and non-zero! You said [$digits]\n"
unless( $digits > 0 and $digits % 2 == 0 and int($digits) eq $digits );
my $k = ( $digits / 2 );
foreach my $n ( 10**($k-1) .. 10**($k) - 1 ) {
my $front = $n*(10**$k + $n);
my $root = int( sqrt( $front ) );
foreach my $try ( $root - 2 .. $root + 2 ) {
my $back = $try * ($try - 1);
last if length($try) > $k;
last if $back > $front;
# say "\tn: $n back: $back try: $try front: $front";
if( $back == $front ) {
say "$n$try";
last;
}
}
}
I'm using the pre-compiled Julia for Mac OS X since I couldn't get the source to compile (but I didn't try beyond it blowing up the first time). I figure that's part of it.
Also, I see about a 0.7 second start up time for any Julia program (see Slow Julia Startup Time), which means the equivalent compiled C program can run about 200 times before Julia finishes once. As the runtime increases (bigger values of digits
) and the startup time means less, my Julia program is still really slow.
I haven't gotten to the part for very large numbers (20+ digit excellent numbers) which I didn't realize Julia doesn't handle those any better than most other languages.
Here's my C code, which is a little different from when I started this. My rusty, inelegant C skills are essentially the same thing as my Perl.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] ) {
long
k, digits,
start, end,
a, b,
front, back,
root
;
digits = atoi( argv[1] );
k = digits / 2;
start = (long) pow(10, k - 1);
end = (long) pow(10, k);
for( a = start; a < end; a++ ) {
front = (long) a * ( pow(10,k) + a );
root = (long) floor( sqrt( front ) );
for( b = root - 1; b <= root + 1; b++ ) {
back = (long) b * ( b - 1 );
if( back > front ) { break; }
if( log10(b) > k ) { continue; }
if( front == back ) {
printf( "%ld%ld\n", a, b );
}
}
}
return 0;
}