This post is part of a series on Mohammad Anwar’s excellent Weekly Challenge, where hackers submit solutions in Perl, Raku, or any other language, to two different challenges every week. (It’s a lot of fun, if you’re into that sort of thing.)
Task #2 this week asks us to calculate a so called Home prime. Home primes are found by factoring a number and concatenating the prime factors (including powers, so 20 = 5×2×2), and repeating this until the result is a prime number.
The given example, HP(10) can be found via the following steps: HP(10) = HP(25) = HP(55) = HP(511) = HP(773), and we stop, since 773 is a prime number.
This is a natural problem for recursion:
sub home_prime_recursive { my @fac = factor( $_ [0]); @fac == 1 ? $_ [0] : home_prime( join '' , @fac ); } |
I like this solution for its expressiveness, but it’s about 20% slower than the following iterative version:
sub home_prime_iterative { my $n = shift ; while (( my @fac = factor( $n )) > 1) { $n = join '' , @fac ; } return $n ; } |
Note that the logic is identical between the two examples; it’s just expressed as a loop conditional and jump versus a conditional and tail call in the preceding example. The difference in performance is down to Perl’s stack and function call overhead. Even using goto &home_prime
to manually enforce tail call optimization resulted in zero speedup from the above recursive solution. Language quirks like this don’t matter 90% of the time, but it pays to keep them in the back of your mind for the 10% of cases that need to be optimized.
Raku
Extremely similar to the recursive Perl version.
use Prime::Factor; sub home_prime( $n ) { my @fac = prime-factors( $n ); @fac .elems == 1 ?? $n !! home_prime( @fac . join ); } |