carmichael_numbers_in_range.pl 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 27 August 2022
  4. # https://github.com/trizen
  5. # Generate all the Carmichael numbers 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. # https://trizenx.blogspot.com/2020/08/pseudoprimes-construction-methods-and.html
  9. # PARI/GP program (in range) (simple):
  10. # carmichael(A, B, k) = A=max(A, vecprod(primes(k+1))\2); (f(m, l, lo, k) = my(list=List()); my(hi=sqrtnint(B\m, k)); if(k==1, forprime(p=max(lo, ceil(A/m)), hi, my(t=m*p); if((t-1)%l == 0 && (t-1)%(p-1) == 0, listput(list, t))), forprime(p = lo, hi, my(t = m*p); my(L=lcm(l, p-1)); if(gcd(L, t) == 1, list=concat(list, f(t, L, p+1, k-1))))); list); vecsort(Vec(f(1, 1, 3, k)));
  11. # PARI/GP program (in range) (fast):
  12. # carmichael(A, B, k) = A=max(A, vecprod(primes(k+1))\2); my(max_p=(1+sqrtint(8*B+1))\4); (f(m, l, lo, k) = my(list=List()); my(hi=min(max_p, sqrtnint(B\m, k))); if(lo > hi, return(list)); if(k==1, lo=max(lo, ceil(A/m)); my(t=lift(1/Mod(m,l))); while(t < lo, t += l); forstep(p=t, hi, l, if(isprime(p), my(n=m*p); if((n-1)%(p-1) == 0, listput(list, n)))), forprime(p=lo, hi, if(gcd(m, p-1) == 1, list=concat(list, f(m*p, lcm(l, p-1), p+1, k-1))))); list); vecsort(Vec(f(1, 1, 3, k)));
  13. # PARI/GP program to generate all the Carmichael numbers <= n (fast):
  14. # carmichael(A, B, k) = A=max(A, vecprod(primes(k+1))\2); my(max_p=(1+sqrtint(8*B+1))\4); (f(m, l, lo, k) = my(list=List()); my(hi=min(max_p, sqrtnint(B\m, k))); if(lo > hi, return(list)); if(k==1, lo=max(lo, ceil(A/m)); my(t=lift(1/Mod(m,l))); while(t < lo, t += l); forstep(p=t, hi, l, if(isprime(p), my(n=m*p); if((n-1)%(p-1) == 0, listput(list, n)))), forprime(p=lo, hi, if(gcd(m, p-1) == 1, list=concat(list, f(m*p, lcm(l, p-1), p+1, k-1))))); list); f(1, 1, 3, k);
  15. # upto(n) = my(list=List()); for(k=3, oo, if(vecprod(primes(k+1))\2 > n, break); list=concat(list, carmichael(1, n, k))); vecsort(Vec(list));
  16. use 5.020;
  17. use warnings;
  18. use ntheory qw(:all);
  19. use experimental qw(signatures);
  20. sub divceil ($x, $y) { # ceil(x/y)
  21. (($x % $y == 0) ? 0 : 1) + divint($x, $y);
  22. }
  23. sub carmichael_numbers_in_range ($A, $B, $k) {
  24. $A = vecmax($A, pn_primorial($k + 1) >> 1);
  25. # Largest possisble prime factor for Carmichael numbers <= B
  26. my $max_p = (1 + sqrtint(8 * $B + 1)) >> 2;
  27. my @list;
  28. sub ($m, $L, $lo, $k) {
  29. my $hi = rootint(divint($B, $m), $k);
  30. if ($lo > $hi) {
  31. return;
  32. }
  33. if ($k == 1) {
  34. $hi = $max_p if ($hi > $max_p);
  35. $lo = vecmax($lo, divceil($A, $m));
  36. $lo > $hi && return;
  37. my $t = invmod($m, $L);
  38. $t > $hi && return;
  39. $t += $L * divceil($lo - $t, $L) if ($t < $lo);
  40. for (my $p = $t ; $p <= $hi ; $p += $L) {
  41. if (($m * $p - 1) % ($p - 1) == 0 and is_prime($p)) {
  42. push @list, $m * $p;
  43. }
  44. }
  45. return;
  46. }
  47. foreach my $p (@{primes($lo, $hi)}) {
  48. if (gcd($m, $p >> 1) == 1) {
  49. __SUB__->($m * $p, lcm($L, $p - 1), $p + 1, $k - 1);
  50. }
  51. }
  52. }
  53. ->(1, 1, 3, $k);
  54. return sort { $a <=> $b } @list;
  55. }
  56. # Generate all the 5-Carmichael numbers in the range [100, 10^8]
  57. my $k = 5;
  58. my $from = 100;
  59. my $upto = 1e8;
  60. my @arr = carmichael_numbers_in_range($from, $upto, $k);
  61. say join(', ', @arr);
  62. __END__
  63. 825265, 1050985, 9890881, 10877581, 12945745, 13992265, 16778881, 18162001, 27336673, 28787185, 31146661, 36121345, 37167361, 40280065, 41298985, 41341321, 41471521, 47006785, 67371265, 67994641, 69331969, 74165065, 75151441, 76595761, 88689601, 93614521, 93869665