Advent Calendar 2022
| Day 10 | Day 11 | Day 12 |
The gift is presented by Flavio Poletti
. Today he is talking about his solution to “The Weekly Challenge - 153”. This is re-produced for Advent Calendar 2022 from the original post by him.
PWC153 - Factorions
TL;DR
On with TASK #2 from The Weekly Challenge #153
. Enjoy!
The challenge
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.
Example 1
Input: $n = 145
Output: 1
Since 1! + 4! + 5! => 1 + 24 + 120 = 145
Example 2
Input: $n = 123
Output: 0
Since 1! + 2! + 3! => 1 + 2 + 6 <> 123
The questions
… does the challenge puzzle say anything about the base we are supposed to consider for figuring out the digits? Is base 10 fair enough?
The solution
OK, let’s start with a blunt implementation of the test in Perl:
#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
use List::Util 'sum';
say is_factorion(shift // 145) ? 1 : 0;
sub is_factorion ($n) {
state $f = [ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 ];
$n == sum map { $f->[$_] } split m{}mxs, $n;
}
We only need factorials up to 9
here, so it makes sense to avoid implementing the factorial function altogether and use a state
variable to keep them.
Now, let’s switch the brain on.
It’s intuitive that there can be only a finite amount of factorions, whatever the base. As an example, in base 10 the maximum contribution to the sum is from digit 9, which provides a whopping 362880
. Not bad, but it’s still a finite and limited contribution to be compared against exponentially growing numbers as we add more digits.
So, for example, the sequence of 9999999
(seven 9) yields a sum of all factorials of the digits that is a mere 2540160
(seven digits, but clearly less than the original). As a matter of fact, it’s impossible to go beyond 2540160
with seven digits, and eight digits or more numbers are of course out of reach.
So… it makes sense to look for all factorions in base 10:
#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
use List::Util 'sum';
# find out the limit. With a given amount of 9 we can only go "some"
# far, so there's no point going beyond that maximum point.
my $s = '';
while ('necessary') {
$s .= '9';
last if $s > sumfact($s);
}
# find out all factorions (up to that limit)
for my $n (0 .. sumfact($s)) {
say $n if $n == sumfact($n);
}
sub sumfact ($n) {
state $f = [ 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 ];
sum map { $f->[$_] } split m{}mxs, $n;
}
It seems that there are not that many:
1
2
145
40585
This leads us to our Raku solution:
#!/usr/bin/env raku
use v6;
sub MAIN (Int:D $n = 145) { put is-factorion($n) ?? 1 !! 0 }
sub is-factorion (Int:D $n where $n >= 0) {
state %factorions = set(1, 2, 145, 40585);
return $n ∈ %factorions;
}
So cool!
If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.