prog.pl 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #!/usr/bin/perl
  2. # Least non-palindromic number k such that k and its digital reversal both have exactly n prime divisors.
  3. # https://oeis.org/A113548
  4. # Known terms:
  5. # 13, 12, 132, 1518, 15015, 204204, 10444434, 241879638, 20340535215, 242194868916
  6. # a(n) >= A239696(n).
  7. # This sequence does not allow ending in 0, else a(8) = 208888680, a(11) = 64635504163230 and a(13) = 477566276048801940. - Michael S. Branicky, Feb 14 2023
  8. # New terms:
  9. # a(11) = 136969856585562
  10. # a(12) = 2400532020354468
  11. # a(13) = 484576809394483806
  12. # a(14) = 200939345091539746692
  13. # Upper-bounds:
  14. # a(13) <= 604973037030580218
  15. # a(14) <= 202183806462387575826
  16. # Lower-bounds:
  17. # a(14) > 107173980829040893951
  18. # Timings:
  19. # a(11) is found in 5.7 seconds
  20. # a(12) is found in 4.8 seconds
  21. # a(13) is found in 2.5 minutes
  22. # MPU::GMP prime_omega:
  23. # a(11) in 19.0 seconds
  24. # a(12) in 14.5 seconds
  25. # Our method:
  26. # a(11) in 9.7 seconds -- 7.8 seconds -- 6.5 seconds
  27. # a(12) in 7.2 seconds -- 5.8 seconds -- 5.3 seconds
  28. # While searching for a(14), it took 21 hours and 30 minutes to check the range [107173980829040893951, 214347961658081787902].
  29. use 5.020;
  30. use warnings;
  31. use ntheory qw(:all);
  32. use experimental qw(signatures);
  33. use Math::GMPz;
  34. use Math::Prime::Util::GMP;
  35. sub mpz_is_omega_prime ($n, $k) {
  36. state $z = Math::GMPz::Rmpz_init();
  37. state $t = Math::GMPz::Rmpz_init();
  38. Math::GMPz::Rmpz_set_str($z, $n, 10);
  39. Math::GMPz::Rmpz_root($t, $z, $k);
  40. my $trial_limit = Math::GMPz::Rmpz_get_ui($t);
  41. if ($trial_limit > 1e3) {
  42. $trial_limit = 1e3;
  43. }
  44. for (my $p = 2; $p <= $trial_limit; $p = next_prime($p)) {
  45. if (Math::GMPz::Rmpz_divisible_ui_p($z, $p)) {
  46. --$k;
  47. Math::GMPz::Rmpz_set_ui($t, $p);
  48. Math::GMPz::Rmpz_remove($z, $z, $t);
  49. }
  50. ($k > 0) or last;
  51. if (Math::GMPz::Rmpz_fits_ulong_p($z)) {
  52. return is_omega_prime($k, Math::GMPz::Rmpz_get_ui($z));
  53. }
  54. }
  55. if (Math::GMPz::Rmpz_cmp_ui($z, 1) == 0) {
  56. return ($k == 0);
  57. }
  58. if ($k == 0) {
  59. return (Math::GMPz::Rmpz_cmp_ui($z, 1) == 0);
  60. }
  61. if ($k == 1) {
  62. if (Math::GMPz::Rmpz_fits_ulong_p($z)) {
  63. return is_prime_power(Math::GMPz::Rmpz_get_ui($z));
  64. }
  65. return Math::Prime::Util::GMP::is_prime_power(Math::GMPz::Rmpz_get_str($z, 10));
  66. }
  67. Math::GMPz::Rmpz_ui_pow_ui($t, next_prime($trial_limit), $k);
  68. if (Math::GMPz::Rmpz_cmp($z, $t) < 0) {
  69. return 0;
  70. }
  71. Math::GMPz::Rmpz_fits_ulong_p($z)
  72. ? is_omega_prime($k, Math::GMPz::Rmpz_get_ui($z))
  73. : (Math::Prime::Util::GMP::prime_omega(Math::GMPz::Rmpz_get_str($z, 10)) == $k);
  74. }
  75. foreach my $n (1..100) {
  76. my $t = addint(urandomb($n), 1);
  77. foreach my $k (1..20) {
  78. if (is_omega_prime($k, $t)) {
  79. mpz_is_omega_prime($t, $k) || die "error for: ($t, $k)";
  80. }
  81. elsif (mpz_is_omega_prime($t, $k)) {
  82. die "counter-example: ($t, $k)";
  83. }
  84. }
  85. }
  86. sub generate($A, $B, $n) {
  87. $A = vecmax($A, pn_primorial($n));
  88. $A = Math::GMPz->new("$A");
  89. my $u = Math::GMPz::Rmpz_init();
  90. my @values = sub ($m, $lo, $j) {
  91. Math::GMPz::Rmpz_tdiv_q($u, $B, $m);
  92. Math::GMPz::Rmpz_root($u, $u, $j);
  93. my $hi = Math::GMPz::Rmpz_get_ui($u);
  94. if ($lo > $hi) {
  95. return;
  96. }
  97. my @lst;
  98. my $v = Math::GMPz::Rmpz_init();
  99. foreach my $q (@{primes($lo, $hi)}) {
  100. if ($q == 5 && Math::GMPz::Rmpz_even_p($m)) {
  101. # Last digit can't be zero
  102. next;
  103. }
  104. Math::GMPz::Rmpz_mul_ui($v, $m, $q);
  105. while (Math::GMPz::Rmpz_cmp($v, $B) <= 0) {
  106. if ($j == 1) {
  107. if (Math::GMPz::Rmpz_cmp($v, $A) >= 0) {
  108. my $s = Math::GMPz::Rmpz_get_str($v, 10);
  109. my $r = reverse($s);
  110. if ($r ne $s and (($r > ~0) ? mpz_is_omega_prime($r, $n) : is_omega_prime($n, $r))) {
  111. my $w = Math::GMPz::Rmpz_init_set($v);
  112. say("Found upper-bound: ", $w);
  113. $B = $w if ($w < $B);
  114. push @lst, $w;
  115. }
  116. }
  117. }
  118. else {
  119. push @lst, __SUB__->($v, $q+1, $j-1);
  120. }
  121. Math::GMPz::Rmpz_mul_ui($v, $v, $q);
  122. }
  123. }
  124. return @lst;
  125. }->(Math::GMPz->new(1), 2, $n);
  126. return sort { $a <=> $b } @values;
  127. }
  128. sub a($n) {
  129. if ($n == 0) {
  130. return 1;
  131. }
  132. #my $x = Math::GMPz->new(pn_primorial($n));
  133. my $x = Math::GMPz->new("107173980829040893951");
  134. my $y = 2*$x;
  135. while (1) {
  136. say("Sieving range: [$x, $y]");
  137. my @v = generate($x, $y, $n);
  138. if (scalar(@v) > 0) {
  139. return $v[0];
  140. }
  141. $x = $y+1;
  142. $y = 2*$x;
  143. }
  144. }
  145. foreach my $n (14) {
  146. say "a($n) = ", a($n);
  147. }