k-powerful_numbers_in_range.sf 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 28 February 2021
  4. # https://github.com/trizen
  5. # Fast recursive algorithm for generating all the k-powerful numbers in a given range [a,b].
  6. # A positive integer n is considered k-powerful, if for every prime p that divides n, so does p^k.
  7. # Example:
  8. # 2-powerful = a^2 * b^3, for a,b >= 1
  9. # 3-powerful = a^3 * b^4 * c^5, for a,b,c >= 1
  10. # 4-powerful = a^4 * b^5 * c^6 * d^7, for a,b,c,d >= 1
  11. # OEIS:
  12. # https://oeis.org/A001694 -- 2-powerful numbers
  13. # https://oeis.org/A036966 -- 3-powerful numbers
  14. # https://oeis.org/A036967 -- 4-powerful numbers
  15. # https://oeis.org/A069492 -- 5-powerful numbers
  16. # https://oeis.org/A069493 -- 6-powerful numbers
  17. func powerful_numbers(A, B, k=2) {
  18. var powerful = []
  19. func (m,r) {
  20. var from = 1
  21. var upto = iroot(idiv(B, m), r)
  22. if (r <= k) {
  23. if (A > m) {
  24. # Optimization by Dana Jacobsen (from Math::Prime::Util::PP)
  25. with (idiv_ceil(A,m)) {|l|
  26. if ((l >> r) == 0) {
  27. from = 2
  28. }
  29. else {
  30. from = l.iroot(r)
  31. from++ if (ipow(from, r) != l)
  32. }
  33. }
  34. }
  35. return nil if (from > upto)
  36. for j in (from .. upto) {
  37. powerful << (m * ipow(j, r))
  38. }
  39. return nil
  40. }
  41. for j in (from .. upto) {
  42. j.is_coprime(m) || next
  43. j.is_squarefree || next
  44. __FUNC__(m * ipow(j, r), r-1)
  45. }
  46. }(1, 2*k - 1)
  47. powerful.sort
  48. }
  49. var a = 1e5.irand
  50. var b = 1e7.irand
  51. for k in (2..5) {
  52. say "Testing: k = #{k}"
  53. assert_eq(
  54. powerful_numbers(a, b, k),
  55. k.powerful(a, b)
  56. )
  57. }
  58. say powerful_numbers(1e6 - 1e4, 1e6, 2) #=> [990025, 990125, 990584, 991232, 992016, 994009, 995328, 996004, 996872, 998001, 998784, 1000000]