fermat_pseudoprimes_p==3_mod_80_in_range.pl 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 28 August 2022
  4. # https://github.com/trizen
  5. # Generate all the squarefree Fermat pseudoprimes to given a base with n prime factors in a given range [a,b]. (not in sorted order)
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Almost_prime
  8. use 5.020;
  9. use ntheory qw(:all);
  10. use experimental qw(signatures);
  11. #use Math::GMP qw(:constant);
  12. sub divceil ($x,$y) { # ceil(x/y)
  13. my $q = divint($x,$y);
  14. ($q*$y == $x) ? $q : ($q+1);
  15. }
  16. sub fermat_pseudoprimes_in_range ($A, $B, $k, $base, $callback) {
  17. my $max_p = 30000;
  18. my $m = 1;
  19. my $L = znorder($base, $m);
  20. $A = $A*$m;
  21. $B = $B*$m;
  22. $A = vecmax($A, pn_primorial($k));
  23. # $A = Math::GMP->new("$A");
  24. # $B = Math::GMP->new("$B");
  25. $B = vecmin($B, 18436227497407654507);
  26. if ($A > $B) {
  27. return;
  28. }
  29. sub ($m, $lambda, $p, $k, $u = undef, $v = undef) {
  30. if ($k == 1) {
  31. # $v = vecmin($v, $max_p);
  32. say "# Sieving: $m -> ($u, $v)" if ($v - $u > 2e6);
  33. if ($v-$u > 1e10) {
  34. die "Range too large!\n";
  35. }
  36. forprimes {
  37. if ($_%80 == 3) {
  38. my $t = $m*$_;
  39. if (($t-1)%$lambda == 0 and ($t-1)%znorder($base, $_) == 0) {
  40. $callback->($t);
  41. }
  42. }
  43. } $u, $v;
  44. return;
  45. }
  46. my $s = rootint(divint($B,$m), $k);
  47. for(my $r; $p <= $s; $p = $r) {
  48. #last if ($p > $max_p);
  49. $r = next_prime($p);
  50. $p % 80 == 3 or next;
  51. if ($base % $p == 0) {
  52. next;
  53. }
  54. if ($m%$p == 0) {
  55. next;
  56. }
  57. my $z = znorder($base, $p);
  58. # is_smooth($z, 200) || next;
  59. my $L = lcm($lambda, $z);
  60. gcd($L, $m) == 1 or next;
  61. my $t = $m*$p;
  62. my $u = divceil($A, $t);
  63. my $v = divint($B,$t);
  64. if ($u <= $v) {
  65. __SUB__->($t, $L, $r, $k - 1, (($k==2 && $r>$u) ? $r : $u), $v);
  66. }
  67. }
  68. }->($m, $L, 3, $k);
  69. return 1;
  70. }
  71. my $base = 2;
  72. my $from = 2;
  73. my $upto = 2*$from;
  74. while (1) {
  75. say "# Range: ($from, $upto)";
  76. foreach my $k (3,5) {
  77. fermat_pseudoprimes_in_range($from, $upto, $k, $base, sub ($n) { say $n }) or next;
  78. }
  79. $from = $upto+1;
  80. $upto = 2*$from;
  81. }