prog.pl 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #!/usr/bin/perl
  2. # Smallest base-2 even pseudoprime (A006935) with exactly n prime factors, or 0 if no such number exists.
  3. # https://oeis.org/A270973
  4. # Known terms:
  5. # 161038, 215326, 209665666, 4783964626, 1656670046626, 1202870727916606
  6. # New terms:
  7. # a(9) = 52034993731418446
  8. # a(10) = 1944276680165220226
  9. # a(11) = 1877970990972707747326
  10. # a(12) = 1959543009026971258888306
  11. # a(13) = 102066199849378101848830606
  12. # Lower-bounds:
  13. # a(12) > 1397223754507606670514567
  14. # a(13) > 41815837812760091234926591
  15. # Upper-bounds:
  16. # a(13) <= 102066199849378101848830606
  17. use 5.020;
  18. use warnings;
  19. use ntheory qw(:all);
  20. use experimental qw(signatures);
  21. use Math::GMPz;
  22. sub fermat_pseudoprimes_in_range ($A, $B, $k, $base, $callback) {
  23. $A = vecmax($A, pn_primorial($k));
  24. $A = Math::GMPz->new("$A");
  25. my $u = Math::GMPz::Rmpz_init();
  26. sub ($m, $lambda, $lo, $j) {
  27. Math::GMPz::Rmpz_tdiv_q($u, $B, $m);
  28. Math::GMPz::Rmpz_root($u, $u, $j);
  29. my $hi = Math::GMPz::Rmpz_get_ui($u);
  30. if ($lo > $hi) {
  31. return;
  32. }
  33. foreach my $p (@{primes($lo, $hi)}) {
  34. if ($base % $p == 0) {
  35. next;
  36. }
  37. my $q = $p;
  38. my $w = Math::GMPz::Rmpz_init();
  39. Math::GMPz::Rmpz_mul_ui($w, $m, $p);
  40. while (Math::GMPz::Rmpz_cmp($w, $B) <= 0) {
  41. my $L = lcm($lambda, znorder($base, $q));
  42. if ($L < ~0) {
  43. Math::GMPz::Rmpz_gcd_ui($Math::GMPz::NULL, $w, $L) == 1 or last;
  44. }
  45. else {
  46. gcd($L, $w) == 1 or last;
  47. }
  48. if ($j == 1) {
  49. if (Math::GMPz::Rmpz_cmp($w, $A) >= 0) {
  50. if ($k == 1 and is_prime($w)) {
  51. ## ok
  52. }
  53. elsif (
  54. ($L < ~0)
  55. ? do {
  56. Math::GMPz::Rmpz_sub_ui($u, $w, 1);
  57. Math::GMPz::Rmpz_divisible_ui_p($u, $L);
  58. }
  59. : (($w - 1) % $L == 0)
  60. ) {
  61. my $t = Math::GMPz::Rmpz_init_set($w);
  62. say "Found upper-bound: $t";
  63. $B = $t if ($t < $B);
  64. $callback->($t);
  65. }
  66. }
  67. }
  68. else {
  69. __SUB__->($w, $L, $p + 1, $j - 1);
  70. }
  71. $q *= $p;
  72. Math::GMPz::Rmpz_mul_ui($w, $w, $p);
  73. }
  74. }
  75. }
  76. ->(Math::GMPz->new(2), 1, 3, $k - 1);
  77. }
  78. sub a ($n) {
  79. if ($n < 3) {
  80. return;
  81. }
  82. my $x = Math::GMPz->new(pn_primorial($n));
  83. #my $x = Math::GMPz->new("41815837812760091234926591");
  84. my $y = 2 * $x;
  85. #my $y = Math::GMPz->new("102066199849378101848830606");
  86. while (1) {
  87. say("Sieving range: [$x, $y]");
  88. my @v;
  89. fermat_pseudoprimes_in_range(
  90. $x, $y, $n, 2,
  91. sub ($k) {
  92. push @v, $k;
  93. }
  94. );
  95. @v = sort { $a <=> $b } @v;
  96. if (scalar(@v) > 0) {
  97. return $v[0];
  98. }
  99. $x = $y + 1;
  100. $y = 2 * $x;
  101. }
  102. }
  103. foreach my $n (10) {
  104. say "a($n) = ", a($n);
  105. }