diff options
| author | drbaggy <js5@sanger.ac.uk> | 2022-02-24 10:10:33 +0000 |
|---|---|---|
| committer | drbaggy <js5@sanger.ac.uk> | 2022-02-24 10:10:33 +0000 |
| commit | 7a40071bbbe445bce92b894ce4057ff2c24242a3 (patch) | |
| tree | cb35c50495700c388f1793ef6effbfb27139b67e /challenge-153 | |
| parent | 894a6ea886be32d28348d0971aae72fdf16db31d (diff) | |
| parent | a6db38cacc0415e95e903ab3c19a983b60d3bbdf (diff) | |
| download | perlweeklychallenge-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.md | 87 |
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. |
