RabbitFarm
2022-02-27
Finding the Factorials and Factorions That Are Left
The examples used here are from The Weekly Challenge problem statement and demonstrate the working solution.
Part 1
Write a script to determine the first ten members of the Left Factorials sequence.
Solution
use strict;
use warnings;
use POSIX;
use constant UPPER_BOUND => INT_MAX/1000;
sub left_factorials_sieve{
my($n) = @_;
my @sieve = (0 .. UPPER_BOUND);
my $x = 2;
{
my @sieve_indices = grep { $_ <= $x || $_ % $x == 0 } 0 .. @sieve - 1;
@sieve = map{ $sieve[$_] } @sieve_indices;
$x++;
redo if $x <= $n;
}
return @sieve[1 .. @sieve - 1];
}
MAIN:{
print join(", ", left_factorials_sieve(10)) . "\n";
}
Sample Run
$ perl perl/ch-1.pl
1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114
Notes
The problem statement for this refers to a On-Line Encyclopedia of Integer Sequences
entry. That OEIS entry mentions some interesting facts about the sequence, including the
sieve technique used here. Officially the sequence seems to start with 0 but since the
example shows it starting with 1 here the initial 0 element is removed.
There is nothing special about the choice of UPPER_BOUND it is just an arbitrarily large
number which fits the purpose. I chose the number via trial and error, but it seems there
is a straightforward provable upper bound U required to get a sequence of required
sequence length N. If this were a math text then I as the author would be compelled to
leave a frustrating note that finding the upper bound is left as an exercise for the
reader. Ha!
Part 2
Write a script to figure out if the given integer is a factorion.
Solution
use strict;
use warnings;
use boolean;
sub factorial{
my($n) = @_;
return 1 if $n == 1;
$n * factorial($n - 1);
}
sub is_factorion{
my($n) = @_;
return boolean($n == unpack("%32I*", pack("I*", map {factorial($_)} split(//, $n))));
}
MAIN:{
print is_factorion(145) . "\n";
print is_factorion(123) . "\n";
}
Sample Run
$ perl perl/ch-2.pl
1
0
Notes
In this solution I tried to optimize for the least amount of code. Not quite a golfed
solution, but compact, to be sure. The digits are obtained via split, passed to our
totally boring recursive factorial() function, the sum of the resulting factorials taken
using pack, and then that sum compared to $n. For convenience in stringifying the
output boolean() is used.
References
posted at: 19:55 by: Adam Russell | path: /perl | permanent link to this entry