count_of_k-powerful_numbers_in_range.pl 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #!/usr/bin/perl
  2. # Author: Trizen
  3. # Date: 28 February 2021
  4. # Edit: 11 April 2024
  5. # https://github.com/trizen
  6. # Fast recursive algorithm for counting the number of k-powerful numbers in a given range [A,B].
  7. # A positive integer n is considered k-powerful, if for every prime p that divides n, so does p^k.
  8. # Example:
  9. # 2-powerful = a^2 * b^3, for a,b >= 1
  10. # 3-powerful = a^3 * b^4 * c^5, for a,b,c >= 1
  11. # 4-powerful = a^4 * b^5 * c^6 * d^7, for a,b,c,d >= 1
  12. # OEIS:
  13. # https://oeis.org/A001694 -- 2-powerful numbers
  14. # https://oeis.org/A036966 -- 3-powerful numbers
  15. # https://oeis.org/A036967 -- 4-powerful numbers
  16. # https://oeis.org/A069492 -- 5-powerful numbers
  17. # https://oeis.org/A069493 -- 6-powerful numbers
  18. # See also:
  19. # https://oeis.org/A118896 -- Number of powerful numbers <= 10^n.
  20. use 5.036;
  21. use ntheory qw(:all);
  22. sub divceil ($x, $y) { # ceil(x/y)
  23. (($x % $y == 0) ? 0 : 1) + divint($x, $y);
  24. }
  25. sub powerful_count_in_range ($A, $B, $k = 2) {
  26. return 0 if ($A > $B);
  27. my $count = 0;
  28. sub ($m, $r) {
  29. my $from = 1;
  30. my $upto = rootint(divint($B, $m), $r);
  31. if ($r <= $k) {
  32. if ($A > $m) {
  33. # Optimization by Dana Jacobsen (from Math::Prime::Util::PP)
  34. my $l = divceil($A, $m);
  35. if (($l >> $r) == 0) {
  36. $from = 2;
  37. }
  38. else {
  39. $from = rootint($l, $r);
  40. $from++ if (powint($from, $r) != $l);
  41. }
  42. }
  43. $count += $upto - $from + 1;
  44. return;
  45. }
  46. foreach my $v ($from .. $upto) {
  47. gcd($m, $v) == 1 or next;
  48. is_square_free($v) or next;
  49. __SUB__->(mulint($m, powint($v, $r)), $r - 1);
  50. }
  51. }
  52. ->(1, 2 * $k - 1);
  53. return $count;
  54. }
  55. require Math::Sidef;
  56. foreach my $k (2 .. 10) {
  57. my $lo = int rand powint(10, $k - 1);
  58. my $hi = int rand powint(10, $k);
  59. my $c1 = powerful_count_in_range($lo, $hi, $k);
  60. my $c2 = Math::Sidef::powerful_count($k, $lo, $hi);
  61. $c1 eq $c2 or die "Error for [$lo, $hi] -- ($c1 != $c2)\n";
  62. printf("Number of %2d-powerful in range 10^j .. 10^(j+1): {%s}\n",
  63. $k, join(", ", map { powerful_count_in_range(powint(10, $_), powint(10, $_ + 1), $k) } 0 .. $k + 7));
  64. }
  65. __END__
  66. Number of 2-powerful in range 10^j .. 10^(j+1): {4, 10, 41, 132, 435, 1409, 4527, 14492, 46188, 146892}
  67. Number of 3-powerful in range 10^j .. 10^(j+1): {2, 5, 13, 32, 79, 179, 407, 933, 2077, 4628, 10242}
  68. Number of 4-powerful in range 10^j .. 10^(j+1): {1, 4, 6, 14, 33, 61, 119, 230, 443, 836, 1572, 2925}
  69. Number of 5-powerful in range 10^j .. 10^(j+1): {1, 2, 5, 8, 16, 32, 55, 95, 165, 285, 495, 848, 1403}
  70. Number of 6-powerful in range 10^j .. 10^(j+1): {1, 1, 4, 6, 9, 17, 33, 52, 86, 130, 217, 350, 552, 876}
  71. 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, 628}
  72. 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, 481}
  73. 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, 390}
  74. 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, 335}