fermat_pseudoprimes_in_range.pl 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 31 August 2022
  4. # https://github.com/trizen
  5. # Generate all the k-omega Fermat pseudoprimes in range [a,b]. (not in sorted order)
  6. # Definition:
  7. # k-omega primes are numbers n such that omega(n) = k.
  8. # See also:
  9. # https://en.wikipedia.org/wiki/Almost_prime
  10. # https://en.wikipedia.org/wiki/Prime_omega_function
  11. # https://trizenx.blogspot.com/2020/08/pseudoprimes-construction-methods-and.html
  12. # PARI/GP program (in range):
  13. # fermat_psp(A, B, k, base=2) = A=max(A, vecprod(primes(k))); (f(m, l, p, j) = my(list=List()); forprime(q=p, sqrtnint(B\m, j), if(base%q != 0, my(z=znorder(Mod(base, q)), L=lcm(l, z)); if(gcd(L, m)==1, my(v=m*q, r=nextprime(q+1)); while(v <= B, if(j==1, if(v>=A && if(k==1, !isprime(v), 1) && (v-1)%l == 0 && (v-1)%z == 0 && Mod(base, v)^(v-1) == 1, listput(list, v)), if(v*r <= B, list=concat(list, f(v, l, r, j-1)))); v *= q)))); list); vecsort(Vec(f(1, 1, 2, k)));
  14. use 5.020;
  15. use warnings;
  16. use ntheory qw(:all);
  17. use experimental qw(signatures);
  18. sub fermat_pseudoprimes ($A, $B, $k, $base, $callback) {
  19. $A = vecmax($A, pn_primorial($k));
  20. sub ($m, $lambda, $p, $j) {
  21. my $s = rootint(divint($B, $m), $j);
  22. for (my $r ; $p <= $s ; $p = $r) {
  23. $r = next_prime($p);
  24. if ($base % $p == 0) {
  25. next;
  26. }
  27. my $z = znorder($base, $p);
  28. my $L = lcm($lambda, $z);
  29. gcd($L, $m) == 1 or next;
  30. for (my $v = $m * $p ; $v <= $B ; $v *= $p) {
  31. if ($j == 1) {
  32. $v >= $A or next;
  33. $k == 1 and is_prime($v) and next;
  34. ($v - 1) % $lambda == 0 or next;
  35. ($v - 1) % $z == 0 or next;
  36. powmod($base, $v - 1, $v) == 1 or next;
  37. $callback->($v);
  38. next;
  39. }
  40. $v * $r <= $B or next;
  41. __SUB__->($v, $L, $r, $j - 1);
  42. }
  43. }
  44. }
  45. ->(1, 1, 2, $k);
  46. }
  47. # Generate all the Fermat pseudoprimes to base 3 in range [1, 10^5]
  48. my $from = 1;
  49. my $upto = 1e5;
  50. my $base = 3;
  51. my @arr;
  52. foreach my $k (1 .. 100) {
  53. last if pn_primorial($k) > $upto;
  54. fermat_pseudoprimes($from, $upto, $k, $base, sub ($n) { push @arr, $n });
  55. }
  56. say join(', ', sort { $a <=> $b } @arr);
  57. __END__
  58. 91, 121, 286, 671, 703, 949, 1105, 1541, 1729, 1891, 2465, 2665, 2701, 2821, 3281, 3367, 3751, 4961, 5551, 6601, 7381, 8401, 8911, 10585, 11011, 12403, 14383, 15203, 15457, 15841, 16471, 16531, 18721, 19345, 23521, 24046, 24661, 24727, 28009, 29161, 29341, 30857, 31621, 31697, 32791, 38503, 41041, 44287, 46657, 46999, 47197, 49051, 49141, 50881, 52633, 53131, 55261, 55969, 63139, 63973, 65485, 68887, 72041, 74593, 75361, 76627, 79003, 82513, 83333, 83665, 87913, 88561, 88573, 88831, 90751, 93961, 96139, 97567