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

Challenge 153

Left Factorial Sequence

Left Factorial

Factorion

posted at: 19:55 by: Adam Russell | path: /perl | permanent link to this entry