strong_fermat_psp_with_n_prime_factors_from_prime_factors_2.pl 4.3 KB

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