aboutsummaryrefslogtreecommitdiff
path: root/challenge-153
diff options
context:
space:
mode:
authordrbaggy <js5@sanger.ac.uk>2022-02-24 10:10:33 +0000
committerdrbaggy <js5@sanger.ac.uk>2022-02-24 10:10:33 +0000
commit7a40071bbbe445bce92b894ce4057ff2c24242a3 (patch)
treecb35c50495700c388f1793ef6effbfb27139b67e /challenge-153
parent894a6ea886be32d28348d0971aae72fdf16db31d (diff)
parenta6db38cacc0415e95e903ab3c19a983b60d3bbdf (diff)
downloadperlweeklychallenge-club-7a40071bbbe445bce92b894ce4057ff2c24242a3.tar.gz
perlweeklychallenge-club-7a40071bbbe445bce92b894ce4057ff2c24242a3.tar.bz2
perlweeklychallenge-club-7a40071bbbe445bce92b894ce4057ff2c24242a3.zip
Merge branch 'master' of github.com:drbaggy/perlweeklychallenge-club
Diffstat (limited to 'challenge-153')
-rw-r--r--challenge-153/james-smith/README.md87
1 files changed, 54 insertions, 33 deletions
diff --git a/challenge-153/james-smith/README.md b/challenge-153/james-smith/README.md
index 0d5719305e..2870ff989f 100644
--- a/challenge-153/james-smith/README.md
+++ b/challenge-153/james-smith/README.md
@@ -29,40 +29,55 @@ say my $t = $f = 1;
say $t += ($f*=$_) for 1..20;
```
-to write out the first 21 (the largest number that can be represented as a an integer in 64bit perl) rather than 10
+to write out the first 21 (the largest number that can be represented as a an integer in 64bit perl) rather than 10.
+
+To get a better formatted output we can run the slightly more verbose script:
+
+```perl
+printf "%26s\n", my $t = my $f = 1;
+printf "%26s\n", scalar reverse ( reverse ($t+=($f*=$_)) =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/gr ) for 1..20;
```
-1
-2
-4
-10
-34
-154
-874
-5914
-46234
-409114
-4037914
-43954714
-522956314
-6749977114
-93928268314
-1401602636314
-22324392524314
-378011820620314
-6780385526348314
-128425485935180314
-2561327494111820314
+
+Which gives the following output...
+
```
+ 1
+ 2
+ 4
+ 10
+ 34
+ 154
+ 874
+ 5,914
+ 46,234
+ 409,114
+ 4,037,914
+ 43,954,714
+ 522,956,314
+ 6,749,977,114
+ 93,928,268,314
+ 1,401,602,636,314
+ 22,324,392,524,314
+ 378,011,820,620,314
+ 6,780,385,526,348,314
+ 128,425,485,935,180,314
+ 2,561,327,494,111,820,314
+```
+
# Challange 2 - Factorions
***You are given an integer, `$n`. Write a script to figure out if the given integer is factorion. A factorion is a natural number that equals the sum of the factorials of its digits.***
## Some notes
-Firstly we need to note that (in base 10) that the largest Factorion would have at most 7 digits. For a given number of digits (m) the largest value of the sum of the digits is
-`9! x m` or `362,880 x m`. For `m=7` we have the largest value being `2,540,160` which has 7-digits, for `m=8` we note that this value `2,903,040` also has 7 digits - so we can't have a solution with 8 or more digits.
+Firstly we need to note that (in base 10) that the largest Factorion would have at most 7 digits. For
+a given number of digits (m) the largest value of the sum of the digits is `9! x m` or `362,880 x m`.
+For `m=7` we have the largest value being `2,540,160` which has 7-digits, for `m=8` we note that this
+value `2,903,040` also has 7 digits - so we can't have a solution with 8 or more digits.
-So when we loop through possibly values we know the limit is actually `2,177,282` greatly reducing our search space (If the value has 7 digits, the first digit must be 1 or 2) then the highest value is `2 + 6 * 9!`.
+So we only need to loop up to `2,540,160` - in fact we can reduce this further as for the 7-digit
+numbers they will either start with 1 or 2. So we can further reduce this to `2 + 6 * 9!` or
+`2,177,282`.
## Solution
@@ -70,13 +85,14 @@ Our is factorion function just adds the factorial digit sum and compares to the
We start with a pre-computed list of factorials as we only need the values for the integers 0..9;
-To avoid having to do a comparison at the end, rather than starting at zero we start at `$n`, so the comparison at the end is just whether or not the sum is `0`.
+To avoid having to do a comparison at the end, rather than starting at zero we start at `$n`,
+so the comparison at the end is just whether or not the sum is `0`.
```perl
my @f = (1);
-push @f, $_*$f[-1] foreach 1..9;
+push @f, $_*$f[-1] foreach 1 .. 9;
-is_factorion($_) && say for 1..2_177_282;
+is_factorion($_) && say for 1 .. 2_177_282;
sub is_factorion {
my $t = $_[0];
@@ -87,18 +103,22 @@ sub is_factorion {
Running this gives the only 4 factorions: `1`, `2`, `145`, `40585`;
-This takes around 3 seconds to run on my test box. To speed this up we can work with groups of up to 4 digits - so we first create the sum arrays for 1, 2, 3 and 4 digits. Note the sum for `20` is different to the sum from `0020` - as `0! = 1`.
+This takes around 3 seconds to run on my test box. To speed this up we can
+work with groups of up to 4 digits - so we first create the sum arrays for
+1, 2, 3 and 4 digits. Note the sum for `20` is different to the sum from
+`0020` - as `0! = 1`.
The code then becomes:
```perl
my @f = (1);
-push @f, $_*$f[-1] foreach 1..9;
+push @f, $_*$f[-1] foreach 1 .. 9;
+
my @z = map { my $t = $_; map {$t+$_} @f }
my @q = map { my $t = $_; map {$t+$_} @f }
my @t = map { my $t = $_; map {$t+$_} @f } @f;
-is_factorion_10k($_) && say for 1..2_177_282;
+is_factorion_10k($_) && say for 1 .. 2_177_282;
sub is_factorion_10k {
my $t = $_[0];
@@ -112,7 +132,8 @@ sub is_factorion_10k {
: $f[ $t ]
);
}
-
```
-This comes in at just less than 1 second - a `4x` speed up. Note the order of the ternaries is important - we start from highest to lowest as it minimizes the average number of comparisions performed.
+This comes in at just less than 1 second - a `4x` speed up. Note the order of the
+ternaries is important - we start from highest to lowest as it minimizes the
+average number of comparisions performed.