count_of_k-powerful_numbers_in_range.sf 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/usr/bin/ruby
  2. # Author: Trizen
  3. # Date: 03 May 2023
  4. # https://github.com/trizen
  5. # Fast recursive algorithm for counting the number of 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. # See also:
  18. # https://oeis.org/A118896 -- Number of powerful numbers <= 10^n.
  19. func powerful_count_in_range(A, B, k=2) {
  20. return 0 if (A > B)
  21. var count = 0
  22. func (m,r) {
  23. var from = 1
  24. var upto = iroot(idiv(B,m), r)
  25. if (r <= k) {
  26. if (A > m) {
  27. # Optimization by Dana Jacobsen (from Math::Prime::Util::PP)
  28. with (idiv_ceil(A,m)) {|l|
  29. if ((l >> r) == 0) {
  30. from = 2
  31. }
  32. else {
  33. from = l.iroot(r)
  34. from++ if (ipow(from, r) != l)
  35. }
  36. }
  37. }
  38. return nil if (from > upto)
  39. count += (upto - from + 1)
  40. return nil
  41. }
  42. each_squarefree(from, upto, {|j|
  43. j.is_coprime(m) || next
  44. __FUNC__(m * j**r, r-1)
  45. })
  46. }(1, 2*k - 1)
  47. return count
  48. }
  49. for k in (2..10) {
  50. var lo = irand(10**(k-1))
  51. var hi = irand(10**k)
  52. assert_eq(powerful_count_in_range(lo, hi, k), k.powerful_count(lo, hi))
  53. printf("Number of %2d-powerful in range 10^j .. 10^(j+1): {%s}\n", k, (7+k).of {|j| powerful_count_in_range(10**j, 10**(j+1), k) }.join(', '))
  54. }
  55. __END__
  56. Number of 2-powerful in range 10^j .. 10^(j+1): {4, 10, 41, 132, 435, 1409, 4527, 14492, 46188}
  57. Number of 3-powerful in range 10^j .. 10^(j+1): {2, 5, 13, 32, 79, 179, 407, 933, 2077, 4628}
  58. Number of 4-powerful in range 10^j .. 10^(j+1): {1, 4, 6, 14, 33, 61, 119, 230, 443, 836, 1572}
  59. Number of 5-powerful in range 10^j .. 10^(j+1): {1, 2, 5, 8, 16, 32, 55, 95, 165, 285, 495, 848}
  60. Number of 6-powerful in range 10^j .. 10^(j+1): {1, 1, 4, 6, 9, 17, 33, 52, 86, 130, 217, 350, 552}
  61. Number of 7-powerful in range 10^j .. 10^(j+1): {1, 0, 3, 6, 6, 10, 20, 32, 53, 76, 115, 178, 267, 412}
  62. Number of 8-powerful in range 10^j .. 10^(j+1): {1, 0, 2, 5, 5, 6, 13, 20, 34, 51, 77, 105, 153, 223, 328}
  63. Number of 9-powerful in range 10^j .. 10^(j+1): {1, 0, 1, 4, 5, 5, 8, 14, 21, 36, 52, 73, 101, 137, 192, 276}
  64. Number of 10-powerful in range 10^j .. 10^(j+1): {1, 0, 0, 4, 4, 5, 7, 7, 15, 25, 37, 52, 73, 96, 126, 175, 238}