aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-148/james-smith/perl/ch-1.pl45
-rw-r--r--challenge-148/james-smith/perl/ch-2.pl57
2 files changed, 96 insertions, 6 deletions
diff --git a/challenge-148/james-smith/perl/ch-1.pl b/challenge-148/james-smith/perl/ch-1.pl
index ade1c05955..8f2d2c10df 100644
--- a/challenge-148/james-smith/perl/ch-1.pl
+++ b/challenge-148/james-smith/perl/ch-1.pl
@@ -9,15 +9,48 @@ use Benchmark qw(cmpthese timethis);
use Data::Dumper qw(Dumper);
my $N = @ARGV ? $ARGV[0] : 1;
-## works for $N up 5...
+
+## works for $N up to 7 (numbers up to but not including 1 sextillion)
+## There are no additional numbers for $N = 8 and 9.
+## Then we have additional numbers for $N = 10 and 11.
+## And then no eban numbers until we get to $N = 22
+## So we need to some more complex code to work from $N=10 onwards
+## as we have no solutions for numbers containing sextillion, septillion
+## decillion to novemdecillion ..
+
my @digits = (0,2,4,6);
my @tens = (0,30,40,50,60);
-my @three_digit_eban_nos = map { my $a=$_; map { $a+$_ } @digits } @tens;
-dump_list( my @next_order = grep {$_} @three_digit_eban_nos );
-dump_list( @next_order = map { my $a = $_; map { sprintf "%s,%03d", $a,$_ } @three_digit_eban_nos } @next_order )
- for 2..$N;
+## We only need to find 2 digit eban numbers here as there are no 3
+## digit eban numbers - hundred contains an "e"...
+
+## We need to dump our first eban numbers!
+
+dump_list(my@eb=grep{$_}my@nx=map{my$a=$_;map{$a+$_}@digits}@tens);
+
+########################################################################
+## Now we extend these by adding more digits at the end so we get those
+## less than 1 million, 1 billion etc.
+## Note there would need to be a slight tweak when we get to sextillion,
+## septillion to skip those numbers
+
+dump_list(@eb=map{my$a=$_;map{sprintf'%s,%03d',$a,$_}@nx}@eb)for 2..$N;
+
+########################################################################
+## Just as an aside the number of eban numbers for $N is precisely
+## 20^$N - 1 (up to including $N==7)
+## The -1 is that the 20^$N includes the number 0 (which a isn't
+## positive but contains a zero anyway if you call it "zero")
+## There is an imprecise nature to this list as the definition does not
+## specify where eban numbers can be negative - if this is the case any
+## +ve eban number has an associated -ve eban number - and visa-versa.
+
+## In dump_list below we remove leading zeros and blank entries
+## To avoid grep - we check to see if $_ is "non-zero"
+## and if it is we add an empty array element rather
+## than blank. This avoids the additional map, and potential double
+## array calculation
sub dump_list {
- say $_ foreach map { $_ ? s{^0+}{}r : () } @_;
+ say for map { $_ ? s{^0+}{}r : () } @_;
}
diff --git a/challenge-148/james-smith/perl/ch-2.pl b/challenge-148/james-smith/perl/ch-2.pl
new file mode 100644
index 0000000000..a7509916b9
--- /dev/null
+++ b/challenge-148/james-smith/perl/ch-2.pl
@@ -0,0 +1,57 @@
+#!/usr/local/bin/perl
+
+use strict;
+
+use warnings;
+use feature qw(say);
+use Test::More;
+use Benchmark qw(cmpthese timethis);
+use Data::Dumper qw(Dumper);
+
+## All solutions where $a < 10,000
+
+## The problem can be re-written as:
+## 8.a^3 + 15.a^2 + 6.a - 27.b^2.c = 1
+## Further mode if we re-write:
+## a = 3.k - 1
+## Then this further reduces to:
+## b^2.c = k^2 . (8.k-3)
+## Where k starts at 1
+
+## This greatly reduces the time it takes to calculate the triplets.
+
+## We loop over $k from 1 .. ($N+1)/3 ## We then loop of $b until such
+## time as the calculated value of $c < 1
+##
+## In this case it is (8*$k-3)*$k*$k / $b*b
+##
+## Trying to avoid issues with rounding due to division we can change
+## this to just
+## (8*$k-3).$k*$k < $b*$b
+##
+## Check to see if the value of $c is an integer and if so display it.
+##
+## It is an integer if $n%$d is zero. Again saves rounding error issues
+
+
+for my $k (1..3333) {
+ for( my ($b, $n) = (1, $k*$k*(8*$k-3) ); $n > $b*$b; $b++ ) {
+ say join "\t", 3*$k-1,$b,$n/$b/$b unless $n%($b*$b);
+ }
+}
+
+## To check the values are truly a Cardano triplet I wrote this
+## function.
+
+sub is_card {
+ my($a,$b,$c) = @_;
+ return abs( cr($a+$b*sqrt$c) + cr($a-$b*sqrt$) - 1 ) < 0.000001;
+}
+
+## To get the cube route - the code would fail if the value
+## was negative. The following works by finding the cube
+## root of the absolute value. And multiplying by -1 if negative
+
+sub cr {
+ return $_[0] < 0 ? -(-$_[0])**(1/3) : $_[0]**(1/3);
+}