# perl6/perl6-examples

New arithmetic solutions

philandstuff committed Sep 6, 2010
1 parent 88492e4 commit 68db7de3e26399c116d7b59b31c864a05a282d8d
Showing with 132 additions and 3 deletions.
1. +4 −3 99-problems/P34-rhebus.pl
2. +35 −0 99-problems/P35-rhebus.pl
3. +38 −0 99-problems/P36-rhebus.pl
4. +55 −0 99-problems/P37-rhebus.pl
 @@ -26,8 +26,8 @@ (Int \$a, Int \$b) # Example 1: iteration -sub totient_phi_i (Int \$n) { - return 1 if \$n ~~ 1; +multi totient_phi_i (1 --> Int) { 1 } +multi totient_phi_i (Int \$n --> Int) { my \$total = 0; for 1..^\$n -> \$k { \$total++ if \$n coprime \$k } return \$total; @@ -38,7 +38,8 @@ (Int \$n) # Example 2: «coprime« hyper operator -sub totient_phi (Int \$n) { +multi totient_phi (1 --> Int) { 1 } +multi totient_phi (Int \$n --> Int) { return 1 if \$n ~~ 1; return [+] (\$n «coprime« list(1..^\$n)); }
 @@ -0,0 +1,35 @@ +use v6; + +# Specification: +# P35 (**) Determine the prime factors of a given positive integer. +# Construct a flat list containing the prime factors in ascending order. +# Example: +# > say ~prime_factors 315 +# 3 3 5 7 + + +sub prime_factors (Int \$n) { + my \$residue = \$n; + gather for (2,3,*+2 ... \$n) -> \$k { + while \$residue %% \$k { + # try 'take 0+\$k' to work around a known rakudo issue (2010-09-05) + take \$k; + \$residue /= \$k; + } + last if \$residue == 1; + # This if block is an optimisation which reduces number of iterations + # for numbers with large prime factors (such as large primes) + # It can be removed without affecting correctness. + if \$k > sqrt \$residue { + take \$residue; + last; + } + } +} + +say ~prime_factors \$_ for 2..20; +say ~prime_factors(315); +say ~prime_factors(1723); + + +# vim:ft=perl6
 @@ -0,0 +1,38 @@ +use v6; + +# Specification: +# P36 (**) Determine the prime factors of a given positive integer (2). +# Construct a list containing the prime factors and their multiplicity. +# Example: +# > prime_factors_mult(315).perl.say +# ([3,2],[5,1],[7,1]) +# +# Hint: The problem is similar to problem P13. + + +sub prime_factors_mult (Int \$n) { + my \$residue = \$n; + gather for (2,3,*+2 ... \$n) -> \$k { + my \$mult=0; + while \$residue %% \$k { + \$mult++; + \$residue div= \$k; + } + take [\$k, \$mult] if \$mult; + last if \$residue == 1; + # This if block is an optimisation which reduces number of iterations + # for numbers with large prime factors (such as large primes) + # It can be removed without affecting correctness. + if \$k > sqrt \$residue { + take [\$residue,1]; + last; + } + } +} + +say prime_factors_mult(\$_).perl for 1..20; +prime_factors_mult(315).perl.say; +prime_factors_mult(1723).perl.say; + + +# vim:ft=perl6
 @@ -0,0 +1,55 @@ +use v6; + +# Specification: +# P37 (**) Calculate Euler's totient function phi(m) (improved). +# See problem P34 for the definition of Euler's totient function. If the +# list of the prime factors of a number m is known in the form of +# problem P36 then the function phi(m) can be efficiently calculated as +# follows: Let ((p1 m1) (p2 m2) (p3 m3) ...) be the list of prime +# factors (and their multiplicities) of a given number m. Then phi(m) +# can be calculated with the following formula: +# +# phi(m) = (p1-1) * p1 ** (m1-1) * (p2-1) * p2 ** (m2-1) +# * (p3-1) * p3 ** (m3-1) * ... + + +# Straight from P36-rhebus.pl +sub prime_factors_mult (Int \$n) { + my \$residue = \$n; + gather for (2,3,*+2 ... \$n) -> \$k { + my \$mult=0; + while \$residue %% \$k { + \$mult++; + \$residue div= \$k; + } + take [\$k, \$mult] if \$mult; + last if \$residue == 1; + if \$k > sqrt \$residue { + take [\$residue,1]; + last; + } + } +} + + +# 1. One-liner version +say "phi(\$_): ", [*] prime_factors_mult(\$_).map({ (\$_[0]-1) * \$_[0] ** (\$_[1]-1) }) + for 1..20; +say [*] prime_factors_mult(315).map: { (\$_[0]-1) * \$_[0] ** (\$_[1]-1) }; + + +# 2. sub version +# note that when prime_factors_mult returns an empty list, [*] returns the +# multiplicative identity 1. This means we don't need to special-case +# totient(1) like in P34-rhebus.pl +sub totient (Int \$n) { + my @factors = prime_factors_mult(\$n); + return [*] @factors.map: { + (\$_[0]-1) * \$_[0] ** (\$_[1]-1) + } +} + +say "phi2(\$_): ", totient(\$_) for 1..20; +say "phi2(315): ", totient(315); + +# vim:ft=perl6