prog-squarefree.pl 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #!/usr/bin/perl
  2. # Smallest base-n Fermat pseudoprime with n distinct prime factors.
  3. # https://oeis.org/A271874
  4. # Known terms:
  5. # 341, 286, 11305, 2203201, 12306385
  6. # New terms found:
  7. # a(7) = 9073150801
  8. # a(8) = 3958035081
  9. # a(9) = 2539184851126
  10. # a(10) = 152064312120721
  11. # a(11) = 10963650080564545
  12. # a(12) = 378958695265110961
  13. # a(13) = 1035551157050957605345
  14. # a(14) = 57044715596229144811105
  15. # a(15) = 6149883077429715389052001
  16. # a(16) = 426634466310819456228926101
  17. # a(17) = 166532358913107245358261399361
  18. # a(18) = 15417816366043964846263074467761
  19. # a(19) = 7512467783390668787701493308514401
  20. # a(20) = 182551639864089765855891394794831841
  21. use 5.020;
  22. use ntheory qw(:all);
  23. use experimental qw(signatures);
  24. #use Math::GMP qw(:constant);
  25. #use Math::AnyNum qw(:overload);
  26. sub divceil ($x,$y) { # ceil(x/y)
  27. my $q = divint($x, $y);
  28. (mulint($q, $y) == $x) ? $q : ($q+1);
  29. }
  30. sub fermat_pseudoprimes_in_range ($A, $B, $k, $base, $callback) {
  31. my $m = 1;
  32. my $L = znorder($base, $m);
  33. $A = mulint($A, $m);
  34. $B = mulint($B, $m);
  35. $A = vecmax($A, pn_primorial($k));
  36. sub ($m, $lambda, $p, $k, $u = undef, $v = undef) {
  37. if ($k == 1) {
  38. say "# Sieving: $m -> ($u, $v)" if ($v - $u > 2e6);
  39. if ($v-$u > 1e10) {
  40. die "Range too large!\n";
  41. }
  42. forprimes {
  43. my $t = mulint($m, $_);
  44. if (modint($t-1, $lambda) == 0 and modint($t-1, znorder($base, $_)) == 0) {
  45. $callback->($t);
  46. }
  47. } $u, $v;
  48. return;
  49. }
  50. my $s = rootint(divint($B, $m), $k);
  51. for(my $r; $p <= $s; $p = $r) {
  52. $r = next_prime($p);
  53. if (modint($m, $p) == 0) {
  54. next;
  55. }
  56. my $t = mulint($m, $p);
  57. my $z = znorder($base, $p) // next;
  58. my $L = lcm($lambda, $z);
  59. gcd($L, $t) == 1 or next;
  60. my $u = divceil($A, $t);
  61. my $v = divint($B, $t);
  62. if ($u <= $v) {
  63. __SUB__->($t, $L, $r, $k - 1, (($k==2 && $r>$u) ? $r : $u), $v);
  64. }
  65. }
  66. }->($m, $L, 2, $k);
  67. }
  68. my $k = 12; # number of prime factors
  69. my $from = 1;
  70. my $upto = 2*$from;
  71. my $base = $k;
  72. while (1) {
  73. say "# Range ($from, $upto)";
  74. my $found = 0;
  75. my $min = undef;
  76. if ($from >= pn_primorial($k)) {
  77. fermat_pseudoprimes_in_range($from, $upto, $k, $base, sub ($n) {
  78. say $n;
  79. $min //= $n;
  80. $found = 1;
  81. if ($n < $min) {
  82. $min = $n;
  83. }
  84. });
  85. }
  86. if ($found) {
  87. say "a($k) = $min";
  88. last;
  89. }
  90. $from = $upto+1;
  91. $upto = $from*2;
  92. }
  93. __END__