dbm2perl_carmichael.pl 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #!/usr/bin/perl
  2. use 5.020;
  3. use autodie;
  4. use warnings;
  5. use Math::GMPz;
  6. use Storable;
  7. use ntheory qw(:all);
  8. use experimental qw(signatures);
  9. use List::Util qw(uniq);
  10. use Math::Prime::Util::GMP;
  11. eval { require GDBM_File };
  12. my $cache_db = "factors.db";
  13. my $storable_file = "factors-carmichael.storable";
  14. dbmopen(my %cache_db, $cache_db, 0444)
  15. or die "Can't create/access database <<$cache_db>>: $!";
  16. sub my_is_carmichael ($n, $factors) {
  17. my $nm1 = Math::GMPz->new($n) - 1;
  18. return if not vecall { Math::GMPz::Rmpz_divisible_p($nm1, Math::GMPz->new($_) - 1) } @$factors;
  19. scalar(uniq(@$factors)) == scalar(@$factors);
  20. }
  21. sub my_is_carmichael_fast ($n, $factors) {
  22. my $nm1 = Math::Prime::Util::GMP::subint($n, 1);
  23. return if not vecall {
  24. Math::Prime::Util::GMP::modint($nm1, ($_ < ~0) ? ($_ - 1) : Math::Prime::Util::GMP::subint($_, 1)) eq '0'
  25. } @$factors;
  26. scalar(uniq(@$factors)) == scalar(@$factors);
  27. }
  28. {
  29. my $nm1 = Math::GMPz::Rmpz_init();
  30. my $pm1 = Math::GMPz::Rmpz_init();
  31. sub my_is_carmichael_faster ($n, $factors) {
  32. Math::GMPz::Rmpz_set_str($nm1, $n, 10);
  33. Math::GMPz::Rmpz_sub_ui($nm1, $nm1, 1);
  34. return if not vecall {
  35. ($_ < ~0) ? Math::GMPz::Rmpz_divisible_ui_p($nm1, $_ - 1) : do {
  36. Math::GMPz::Rmpz_set_str($pm1, $_, 10);
  37. Math::GMPz::Rmpz_sub_ui($pm1, $pm1, 1);
  38. Math::GMPz::Rmpz_divisible_p($nm1, $pm1);
  39. }
  40. } @$factors;
  41. scalar(uniq(@$factors)) == scalar(@$factors);
  42. }
  43. }
  44. my $table = {};
  45. if (-e $storable_file) {
  46. say "# Loading data...";
  47. $table = retrieve($storable_file);
  48. }
  49. say "# Checking database...";
  50. while (my ($key, $value) = each %cache_db) {
  51. next if exists $table->{$key};
  52. #~ Math::Prime::Util::GMP::is_pseudoprime($key,2) || next;
  53. my @factors = split(' ', $value);
  54. if (scalar(@factors) >= 3 and my_is_carmichael_faster($key, \@factors)) {
  55. $table->{$key} = $value;
  56. }
  57. }
  58. say "# Storing data...";
  59. store($table, $storable_file);
  60. dbmclose(%cache_db);