carmichael_generate.pl 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. #!/usr/bin/perl
  2. # Generate Carmichael numbers.
  3. use 5.020;
  4. use warnings;
  5. use experimental qw(signatures);
  6. use Math::AnyNum qw(prod);
  7. use ntheory qw(:all);
  8. use List::Util qw(uniq);
  9. use Math::Prime::Util::GMP qw(is_pseudoprime vecprod is_carmichael);
  10. sub fermat_pseudoprimes ($limit) {
  11. my %common_divisors;
  12. warn "Sieving...\n";
  13. forprimes {
  14. my $p = $_;
  15. my $z1 = znorder(2, $p);
  16. my $z2 = ($p == 3) ? (3-1) : znorder(3, $p);
  17. my $z3 = ($p == 5) ? (5-1) : znorder(5, $p);
  18. my $z4 = ($p == 7) ? (7-1) : znorder(7, $p);
  19. foreach my $d (divisors($p - 1)) {
  20. if (
  21. gcd($d, $z1) == $z1
  22. #and gcd($d, $z2) == $z2
  23. #and gcd($d, $z3) == $z3
  24. and gcd($d, $z4) == $z4
  25. ) {
  26. foreach my $k (1..50) {
  27. push @{$common_divisors{$d*$k}}, $p;
  28. }
  29. }
  30. }
  31. } 3, $limit;
  32. warn "Combinations...\n";
  33. foreach my $arr (values %common_divisors) {
  34. @$arr = uniq(@$arr);
  35. my $l = $#{$arr} + 1;
  36. foreach my $k (3 .. $l) {
  37. forcomb {
  38. my $n = vecprod(@{$arr}[@_]);
  39. if ($n > ~0 and is_carmichael($n)) {
  40. warn "$n\n";
  41. say $n;
  42. }
  43. } $l, $k;
  44. }
  45. }
  46. }
  47. fermat_pseudoprimes(1e5);