prog.pl 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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 Math::GMP qw(:constant);
  21. sub divceil ($x,$y) { # ceil(x/y)
  22. my $q = divint($x, $y);
  23. ($q*$y == $x) ? $q : ($q+1);
  24. }
  25. sub squarefree_fermat_overpseudoprimes_in_range ($A, $B, $k, $base, $callback) {
  26. $A = vecmax($A, pn_primorial($k));
  27. sub ($m, $lambda, $p, $k, $u = undef, $v = undef) {
  28. if ($k == 1) {
  29. if (prime_count($u, $v) < divint($v-$u, $lambda)) {
  30. forprimes {
  31. if (($m*$_ - 1)%$lambda == 0 and powmod($base, $lambda, $_) == 1 and znorder($base, $_) == $lambda) {
  32. $callback->($m*$_);
  33. }
  34. } $u, $v;
  35. return;
  36. }
  37. my $w = $lambda * divceil($u-1, $lambda);
  38. for(; $w <= $v; $w += $lambda) {
  39. if (is_prime($w+1) and powmod($base, $lambda, $w+1) == 1) {
  40. my $p = $w+1;
  41. if (($m*$p - 1)%$lambda == 0 and znorder($base, $p) == $lambda) {
  42. $callback->($m*$p);
  43. }
  44. }
  45. }
  46. return;
  47. }
  48. my $s = rootint(divint($B, $m), $k);
  49. for(my $r; $p <= $s; $p = $r) {
  50. $r = next_prime($p);
  51. $base % $p == 0 and next;
  52. my $L = znorder($base, $p);
  53. $L == $lambda or $lambda == 1 or next;
  54. gcd($L, $m) == 1 or next;
  55. my $t = $m*$p;
  56. my $u = divceil($A, $t);
  57. my $v = divint($B, $t);
  58. if ($u <= $v) {
  59. __SUB__->($t, $L, $r, $k - 1, (($k==2 && $r>$u) ? $r : $u), $v);
  60. }
  61. }
  62. }->(1, 1, 2, $k);
  63. }
  64. sub a($n) {
  65. my $x = pn_primorial($n);
  66. my $y = 2*$x;
  67. $x = Math::GMP->new("$x");
  68. $y = Math::GMP->new("$y");
  69. for (;;) {
  70. my @arr;
  71. squarefree_fermat_overpseudoprimes_in_range($x, $y, $n, 2, sub($v) { push @arr, $v });
  72. if (@arr) {
  73. @arr = sort {$a <=> $b} @arr;
  74. return $arr[0];
  75. }
  76. $x = $y+1;
  77. $y = 2*$x;
  78. }
  79. }
  80. foreach my $n (2..100) {
  81. say "a($n) = ", a($n);
  82. }