factors_of_2^n-1_overpseudoprimes.pl 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. #!/usr/bin/perl
  2. # Find overpseudoprimes with small znorder z. Such pseudoprimes divide 2^z - 1.
  3. use 5.020;
  4. use strict;
  5. use warnings;
  6. use Storable;
  7. use Math::GMPz;
  8. use ntheory qw(:all);
  9. use Math::Prime::Util::GMP;
  10. use experimental qw(signatures);
  11. my $storable_file = "cache/factors-superpsp.storable";
  12. my $numbers = retrieve($storable_file);
  13. sub is_over_pseudoprime_fast ($n, $factors) {
  14. Math::Prime::Util::GMP::is_strong_pseudoprime($n, 2) || return;
  15. my $gcd = Math::Prime::Util::GMP::gcd(map { ($_ < ~0) ? ($_ - 1) : Math::Prime::Util::GMP::subint($_, 1) } @$factors);
  16. Math::Prime::Util::GMP::powmod(2, $gcd, $n) eq '1'
  17. or return;
  18. my $prev;
  19. foreach my $p (@$factors) {
  20. if (defined($prev)) {
  21. if ($p < ~0) {
  22. Math::Prime::Util::powmod(2, $prev, $p) == 1 or return;
  23. }
  24. else {
  25. Math::Prime::Util::GMP::powmod(2, $prev, $p) eq '1' or return;
  26. }
  27. }
  28. my $zn = znorder(2, $p);
  29. if ($zn > 1e6) {
  30. return;
  31. }
  32. if (defined($prev)) {
  33. $zn == $prev or return;
  34. }
  35. else {
  36. $prev = $zn;
  37. }
  38. }
  39. return $prev;
  40. }
  41. my %table;
  42. foreach my $n (sort { log($a) <=> log($b) } keys %$numbers) {
  43. length($n) > 40 or next;
  44. my @factors = split(' ', $numbers->{$n});
  45. my $count = scalar @factors;
  46. length($factors[0]) <= 40 or next;
  47. my $z = is_over_pseudoprime_fast($n, \@factors) // next;
  48. say "2^$z-1 = $n";
  49. }