is_perfect_power_fast.sf 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 05 January 2020
  4. # https://github.com/trizen
  5. # A fast pretest for checking if a number `n` is a perfect power.
  6. # (i.e. can be expressed as: n = a^k with k > 1)
  7. # Algorithm:
  8. # 1. Let `n` be the number to be tested.
  9. # 2. Let `k` be the primorial of `B`.
  10. # 3. Compute the greatest common divisor: `g = gcd(n,k)`.
  11. # 4. If `g` is greater than `1`, then `n = r * g^e`, for some `e >= 1`:
  12. # * if `r = 1` and `e = 1`, then `n` is not a perfect power.
  13. # * if `r = 1` and `e > 1`, then `n` is a perfect power.
  14. # * if `r` is prime, then `n` is not a perfect power. (optional)
  15. # * Factorize `g` into primes `p_k` and compute multiplicity `e_k` in `n`:
  16. # * if `gcd(e_k) = 1`, then `n` is not a perfect power.
  17. # * if `gcd(e_k) = b`, with `b >= 2` and `n = floor(n^(1/b))^b` , then `n` is a perfect power.
  18. # 5. If this step is reached, then `n` is probably a perfect power.
  19. func is_perfect_power_pretest(n,k) {
  20. var g = gcd(n,k)
  21. if (g > 1) {
  22. var e = valuation(n,g)
  23. var r = (n / g**e)
  24. if ((r == 1) && (e == 1)) {
  25. return false
  26. }
  27. if ((r == 1) && (e > 1)) {
  28. return true
  29. }
  30. var f = g.factor.map {|p|
  31. [p, n.valuation(p)]
  32. }
  33. var b = f.map { .tail }.gcd
  34. if (b == 1) {
  35. return false
  36. }
  37. var t = (n / f.prod_2d {|p,e| p**e })
  38. if (t.is_prime) {
  39. return false
  40. }
  41. }
  42. if (n.is_prime) {
  43. return false
  44. }
  45. return true
  46. }
  47. func is_perfect_power(n) {
  48. for k in (n.ilog2 `downto` 2) {
  49. if (n.iroot(k)**k == n) {
  50. return k
  51. }
  52. }
  53. return 1
  54. }
  55. say is_perfect_power(1234**14) #=> 14
  56. say is_perfect_power(27*49) #=> 1
  57. var k = 29.primorial
  58. say is_perfect_power_pretest(1234**14, k) #=> true
  59. say is_perfect_power_pretest(27*49, k) #=> false
  60. var a = (2..1000 -> grep { is_perfect_power(_) > 1 })
  61. var b = (2..1000 -> grep { is_perfect_power_pretest(_, k) })
  62. assert_eq(a, b)