generate_chebyshev_pseudoprimes.pl 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #!/usr/bin/perl
  2. # Generate Chebyshev pseudoprimes.
  3. # https://oeis.org/A175530
  4. use 5.020;
  5. use warnings;
  6. use ntheory qw(:all);
  7. use experimental qw(signatures);
  8. sub divceil ($x,$y) { # ceil(x/y)
  9. my $q = divint($x, $y);
  10. ($q*$y == $x) ? $q : ($q+1);
  11. }
  12. sub carmichael_numbers_in_range ($A, $B, $k, $callback) {
  13. my $max_p = 3457;
  14. $A = vecmax($A, pn_primorial($k+1)>>1);
  15. sub ($m, $lambda, $lambda2, $p, $k, $u = undef, $v = undef) {
  16. if (defined($u) and $u > $v) {
  17. return;
  18. }
  19. if ($k == 1) {
  20. $v = vecmin($v, $max_p);
  21. if ($u > $v) {
  22. return;
  23. }
  24. forprimes {
  25. my $t = $m*$_;
  26. my $l1 = lcm($lambda, $_-1);
  27. my $l2 = lcm($lambda2, $_+1);
  28. my $x = $t % $l1;
  29. my $y = $t % $l2;
  30. if (($x == 1 or $x == $l1-1) and ($y == 1 or $y == $l2-1)) {
  31. $callback->($t);
  32. }
  33. } $u, $v;
  34. return;
  35. }
  36. my $s = rootint(divint($B, $m), $k);
  37. for (my $r; $p <= $s; $p = $r) {
  38. last if ($p > $max_p);
  39. $r = next_prime($p);
  40. is_smooth($p - 1, 127) || next;
  41. is_smooth($p + 1, 191) || next;
  42. is_smooth($p*$p - 1, 191) || next;
  43. #is_smooth($p*$p - 1, 127) || next;
  44. my $L = lcm($lambda, $p-1);
  45. gcd($L, $m) == 1 or next;
  46. my $L2 = lcm($lambda2, $p+1);
  47. gcd($L2, $m) == 1 or next;
  48. #is_smooth($p*$p - 1, 127) || next;
  49. #is_smooth($p - 1, 19) || next;
  50. # gcd($m*$p, euler_phi($m*$p)) == 1 or die "$m*$p: not cyclic";
  51. my $t = $m*$p;
  52. my $u = divceil($A, $t);
  53. my $v = divint($B, $t);
  54. if ($u <= $v) {
  55. __SUB__->($t, $L, $L2, $r, $k - 1, (($k==2 && $r>$u) ? $r : $u), $v);
  56. }
  57. }
  58. }->(Math::GMPz->new(1), 1, 1, 3, $k);
  59. }
  60. use Math::GMPz;
  61. my $k = 14;
  62. #my $from = Math::GMPz->new("1");
  63. #my $upto = $from+100;
  64. my $from = Math::GMPz->new("734097107648270852639");
  65. my $upto = 2*$from;
  66. while (1) {
  67. say ":: [$k] Sieving ($from, $upto)";
  68. carmichael_numbers_in_range($from, $upto, $k, sub ($n) { say $n });
  69. $from = $upto+1;
  70. $upto = 2*$from;
  71. }