strong_carmichael_with_n_prime_factors_from_prime_factors.pl 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 24 September 2022
  4. # https://github.com/trizen
  5. use 5.020;
  6. use warnings;
  7. use ntheory qw(:all);
  8. use experimental qw(signatures);
  9. use Math::GMPz;
  10. sub divceil ($x, $y) { # ceil(x/y)
  11. my $q = ($x / $y);
  12. ($q * $y == $x) ? $q : ($q + 1);
  13. }
  14. sub strong_fermat_psp_in_range ($A, $B, $k, $base, $primes, $callback) {
  15. $A = vecmax($A, pn_primorial($k));
  16. $A = Math::GMPz->new("$A");
  17. if ($A > $B) {
  18. return;
  19. }
  20. my $end = $#{$primes};
  21. my $k_exp = 1;
  22. my $congr = -1;
  23. sub ($m, $lambda, $j, $k) {
  24. my $y = rootint(($B / $m), $k);
  25. if ($k == 1) {
  26. my $x = divceil($A, $m);
  27. if ($primes->[-1] < $x) {
  28. return;
  29. }
  30. foreach my $i ($j .. $end) {
  31. my $p = $primes->[$i];
  32. last if ($p > $y);
  33. next if ($p < $x);
  34. my $valuation = valuation($p - 1, 2);
  35. ($valuation > $k_exp and powmod($base, (($p - 1) >> $valuation) << $k_exp, $p) == ($congr % $p)) || next;
  36. my $t = $m * $p;
  37. if (($t - 1) % $lambda == 0 and ($t - 1) % ($p-1) == 0) {
  38. $callback->($t);
  39. }
  40. }
  41. return;
  42. }
  43. foreach my $i ($j .. $end) {
  44. my $p = $primes->[$i];
  45. last if ($p > $y);
  46. $base % $p == 0 and next;
  47. my $valuation = valuation($p - 1, 2);
  48. $valuation > $k_exp or next;
  49. powmod($base, (($p - 1) >> $valuation) << $k_exp, $p) == ($congr % $p) or next;
  50. my $L = lcm($lambda, $p-1);
  51. gcd($L, $m) == 1 or next;
  52. my $t = $m * $p;
  53. my $u = divceil($A, $t);
  54. my $v = ($B / $t);
  55. if ($u <= $v) {
  56. __SUB__->($t, $L, $i + 1, $k - 1);
  57. }
  58. }
  59. }
  60. ->(Math::GMPz->new(1), 1, 0, $k);
  61. }
  62. use IO::Handle;
  63. open my $fh, '>>', 'strong_carmichael.txt';
  64. $fh->autoflush(1);
  65. #~ a(12) <= 27146803388402594456683201
  66. #~ a(13) <= 1793888484612948579347804219906251
  67. #~ a(14) <= 189584826452674863676897122014401
  68. #~ a(15) <= 82118192385977491711980768883709401
  69. my %upper_bounds = (
  70. 11 => Math::GMPz->new("40458813831093914176528685701"),
  71. 12 => Math::GMPz->new("27146803388402594456683201"),
  72. 13 => Math::GMPz->new("1793888484612948579347804219906251"),
  73. 14 => Math::GMPz->new("189584826452674863676897122014401"),
  74. 15 => Math::GMPz->new("82118192385977491711980768883709401"),
  75. #~ 19 => Math::GMPz->new("639480457556385948331213272814418836890728227501"),
  76. #~ 20 => Math::GMPz->new("639480457556385948331213272814418836890728227501000"),
  77. );
  78. use List::Util qw(shuffle);
  79. #foreach my $lambda (80000 .. 1e6) {
  80. foreach my $lambda (shuffle 812700, 139230, 3197250, 4709250, 4709250, 2174130, 8824410, 20396250, 10442250, 982800, 7068600, 116953200, 88, 360, 3024, 12852, 8400, 39984, 18900, 486864, 529200) {
  81. #while (<>) {
  82. # chomp(my $lambda = $_);
  83. #$lambda >= 96600 or next;
  84. say "# Generating: $lambda";
  85. my @primes = grep { $_ > 2 and $lambda % $_ != 0 and $_ <= 3000 and is_prime($_) } map { $_ + 1 } divisors($lambda);
  86. foreach my $k (11..15) {
  87. #if (binomial(scalar(@primes), $k) < 1e6) {
  88. strong_fermat_psp_in_range(Math::GMPz->new(~0), $upper_bounds{$k}, $k, 2, \@primes, sub ($n) { say $n; say $fh $n; });
  89. #}
  90. }
  91. }