squarefree_strong_fermat_pseudoprimes_to_multiple_bases_in_range.pl 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 09 March 2023
  4. # https://github.com/trizen
  5. # Generate all the squarefree k-omega strong Fermat pseudoprimes in range [A,B] to multiple given bases. (not in sorted order)
  6. # See also:
  7. # https://trizenx.blogspot.com/2020/08/pseudoprimes-construction-methods-and.html
  8. use 5.036;
  9. use ntheory qw(:all);
  10. sub divceil ($x, $y) { # ceil(x/y)
  11. (($x % $y == 0) ? 0 : 1) + divint($x, $y);
  12. }
  13. sub squarefree_strong_fermat_pseudoprimes_in_range ($A, $B, $k, $bases) {
  14. $A = vecmax($A, pn_primorial($k));
  15. $A > $B and return;
  16. my @bases = @$bases;
  17. my $bases_lcm = lcm(@bases);
  18. my @list;
  19. sub ($m, $L, $lo, $k) {
  20. my $hi = rootint(divint($B, $m), $k);
  21. if ($lo > $hi) {
  22. return;
  23. }
  24. if ($k == 1) {
  25. $lo = vecmax($lo, divceil($A, $m));
  26. $lo > $hi && return;
  27. my $t = invmod($m, $L) // return;
  28. $t > $hi && return;
  29. $t += $L * divceil($lo - $t, $L) if ($t < $lo);
  30. for (my $p = $t ; $p <= $hi ; $p += $L) {
  31. if (is_prime($p) and $bases_lcm % $p != 0 and $m % $p != 0) {
  32. my $v = $m * $p;
  33. if (is_strong_pseudoprime($v, @bases)) {
  34. push(@list, $v);
  35. }
  36. }
  37. }
  38. return;
  39. }
  40. foreach my $p (@{primes($lo, $hi)}) {
  41. $bases_lcm % $p == 0 and next;
  42. my $lcm = lcm(map { znorder($_, $p) } @bases);
  43. gcd($m, $lcm) == 1 or next;
  44. __SUB__->($m * $p, lcm($L, $lcm), $p + 1, $k - 1);
  45. }
  46. }
  47. ->(1, 1, 2, $k);
  48. return sort { $a <=> $b } @list;
  49. }
  50. # Generate all the strong Fermat pseudoprimes to base 2,3 in range [1, 54029741]
  51. my $from = 1;
  52. my $upto = 54029741;
  53. my @bases = (2, 3);
  54. my @arr;
  55. foreach my $k (2 .. 100) {
  56. last if pn_primorial($k) > $upto;
  57. push @arr, squarefree_strong_fermat_pseudoprimes_in_range($from, $upto, $k, \@bases);
  58. }
  59. say join(', ', sort { $a <=> $b } @arr);
  60. __END__
  61. 1373653, 1530787, 1987021, 2284453, 3116107, 5173601, 6787327, 11541307, 13694761, 15978007, 16070429, 16879501, 25326001, 27509653, 27664033, 28527049, 54029741