prog_faster.pl 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #!/usr/bin/perl
  2. # Smallest overpseudoprime to base 2 (A141232) with n distinct prime factors.
  3. # https://oeis.org/A353409
  4. # Known terms:
  5. # 2047, 13421773, 14073748835533
  6. # Upper-bounds:
  7. # a(5) <= 1376414970248942474729
  8. # a(6) <= 48663264978548104646392577273
  9. # a(7) <= 294413417279041274238472403168164964689
  10. # a(8) <= 98117433931341406381352476618801951316878459720486433149
  11. # a(9) <= 1252977736815195675988249271013258909221812482895905512953752551821
  12. # New terms confirmed (03 September 2022):
  13. # a(5) = 1376414970248942474729
  14. # a(6) = 48663264978548104646392577273
  15. # a(7) = 294413417279041274238472403168164964689
  16. use 5.020;
  17. use warnings;
  18. use ntheory qw(:all);
  19. use experimental qw(signatures);
  20. use Memoize qw(memoize);
  21. use Math::GMPz;
  22. memoize('inverse_znorder_primes');
  23. sub divceil ($x,$y) { # ceil(x/y)
  24. my $q = divint($x,$y);
  25. ($q*$y == $x) ? $q : ($q+1);
  26. }
  27. sub inverse_znorder_primes($base, $lambda) {
  28. my %seen;
  29. grep { znorder($base, $_) == $lambda } grep { !$seen{$_}++ } factor(subint(powint($base, $lambda), 1));
  30. }
  31. sub squarefree_fermat_overpseudoprimes_in_range ($A, $B, $k, $base, $callback) {
  32. $A = vecmax($A, pn_primorial($k));
  33. sub ($m, $lambda, $p, $k, $u = undef, $v = undef) {
  34. if ($k == 1) {
  35. if ($lambda <= 135) {
  36. foreach my $p (inverse_znorder_primes($base, $lambda)) {
  37. next if $p < $u;
  38. next if $p > $v;
  39. if (($m*$p - 1)%$lambda == 0) {
  40. $callback->($m*$p);
  41. }
  42. }
  43. return;
  44. }
  45. if (prime_count_lower($v)-prime_count_lower($u) < divint($v-$u, $lambda)) {
  46. forprimes {
  47. if (($m*$_ - 1)%$lambda == 0 and powmod($base, $lambda, $_) == 1 and znorder($base, $_) == $lambda) {
  48. $callback->($m*$_);
  49. }
  50. } $u, $v;
  51. return;
  52. }
  53. for(my $w = $lambda * divceil($u-1, $lambda); $w <= $v; $w += $lambda) {
  54. if (is_prime($w+1) and powmod($base, $lambda, $w+1) == 1) {
  55. my $p = $w+1;
  56. if (($m*$p - 1)%$lambda == 0 and znorder($base, $p) == $lambda) {
  57. $callback->($m*$p);
  58. }
  59. }
  60. }
  61. return;
  62. }
  63. my $s = rootint($B/$m, $k);
  64. if ($lambda > 1 and $lambda <= 135) {
  65. for my $q (inverse_znorder_primes($base, $lambda)) {
  66. next if ($q < $p);
  67. next if ($q > $s);
  68. my $t = $m*$q;
  69. my $u = divceil($A, $t);
  70. my $v = $B/$t;
  71. if ($u <= $v) {
  72. my $r = next_prime($q);
  73. __SUB__->($t, $lambda, $r, $k-1, (($k==2 && $r>$u) ? $r : $u), $v);
  74. }
  75. }
  76. return;
  77. }
  78. if ($lambda > 1) {
  79. for(my $w = $lambda * divceil($p-1, $lambda); $w <= $s; $w += $lambda) {
  80. if (is_prime($w+1) and powmod($base, $lambda, $w+1) == 1) {
  81. my $p = $w+1;
  82. $lambda == znorder($base, $p) or next;
  83. $base % $p == 0 and next;
  84. my $t = $m*$p;
  85. my $u = divceil($A, $t);
  86. my $v = $B/$t;
  87. if ($u <= $v) {
  88. my $r = next_prime($p);
  89. __SUB__->($t, $lambda, $r, $k-1, (($k==2 && $r>$u) ? $r : $u), $v);
  90. }
  91. }
  92. }
  93. return;
  94. }
  95. for (my $r; $p <= $s; $p = $r) {
  96. $r = next_prime($p);
  97. $base % $p == 0 and next;
  98. my $L = znorder($base, $p);
  99. $L == $lambda or $lambda == 1 or next;
  100. gcd($L, $m) == 1 or next;
  101. my $t = $m*$p;
  102. my $u = divceil($A, $t);
  103. my $v = $B/$t;
  104. if ($u <= $v) {
  105. __SUB__->($t, $L, $r, $k - 1, (($k==2 && $r>$u) ? $r : $u), $v);
  106. }
  107. }
  108. }->(Math::GMPz->new(1), 1, 2, $k);
  109. }
  110. sub a($n) {
  111. my $x = pn_primorial($n);
  112. my $y = 2*$x;
  113. $x = Math::GMPz->new("$x");
  114. $y = Math::GMPz->new("$y");
  115. for (;;) {
  116. my @arr;
  117. squarefree_fermat_overpseudoprimes_in_range($x, $y, $n, 2, sub($v) { push @arr, $v });
  118. if (@arr) {
  119. @arr = sort {$a <=> $b} @arr;
  120. return $arr[0];
  121. }
  122. $x = $y+1;
  123. $y = 2*$x;
  124. }
  125. }
  126. foreach my $n (8) {
  127. say "a($n) = ", a($n);
  128. }
  129. __END__
  130. a(2) = 2047
  131. a(3) = 13421773
  132. a(4) = 14073748835533
  133. a(5) = 1376414970248942474729
  134. a(6) = 48663264978548104646392577273
  135. a(7) = 294413417279041274238472403168164964689