carmichael_factorization_method_generalized.pl 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 08 May 2019
  4. # https://github.com/trizen
  5. # A simple factorization method, using the binary search algorithm, for numbers of the form:
  6. #
  7. # n = x * Prod_{k=1..r} ((x±1)*a_k ± 1)
  8. #
  9. # for `r` relatively small.
  10. # Many Carmichael numbers and Lucas pseudoprimes are of this form and can be factorized relatively fast by this method.
  11. # See also:
  12. # https://en.wikipedia.org/wiki/Binary_search_algorithm
  13. use 5.024;
  14. use warnings;
  15. use experimental qw(signatures);
  16. use ntheory qw(lastfor forcomb);
  17. use Math::AnyNum qw(:overload bsearch_le iroot prod gcd);
  18. sub carmichael_factorization ($n, $k = 3, $l = 2, $h = 6) {
  19. my @blocks = (
  20. sub ($x, @params) {
  21. map { ($x - 1) * $_ + 1 } @params;
  22. },
  23. sub ($x, @params) {
  24. map { ($x + 1) * $_ - 1 } @params;
  25. },
  26. );
  27. my @factors;
  28. my @range = ($l .. $h);
  29. forcomb {
  30. my @params = @range[@_];
  31. foreach my $block (@blocks) {
  32. my $r = bsearch_le(
  33. iroot($n, $k),
  34. sub ($x) {
  35. (prod($block->($x, @params)) * $x) <=> $n;
  36. }
  37. );
  38. my $g = gcd($r, $n);
  39. if ($g > 1) {
  40. @factors = grep { $n % $_ == 0 } ($r, $block->($r, @params));
  41. @factors = ($g) if !@factors;
  42. lastfor, return @factors;
  43. }
  44. }
  45. } scalar(@range), $k - 1;
  46. return @factors;
  47. }
  48. #<<<
  49. local $, = ", ";
  50. say carmichael_factorization(7520940423059310542039581, 3); #=> 79443853
  51. say carmichael_factorization(570115866940668362539466801338334994649, 3); #=> 4563211789627
  52. say carmichael_factorization(8325544586081174440728309072452661246289, 3); #=> 11153738721817
  53. say '=' x 80;
  54. say carmichael_factorization(60711773123792542753, 4, 2, 10); #=> 2597294701
  55. say carmichael_factorization(73410179782535364796052059, 2, 2, 18); #=> 2141993519227
  56. say carmichael_factorization(12946744736260953126701495197312513, 4, 2, 6); #=> 37927921157953921
  57. say '=' x 80;
  58. say carmichael_factorization(1169586052690021349455126348204184925097724507, 3, 11, 23); #=> 166585508879747
  59. say carmichael_factorization(61881629277526932459093227009982733523969186747, 3, 3, 11); #=> 1233150073853267
  60. say carmichael_factorization(173315617708997561998574166143524347111328490824959334367069087, 3, 3, 11); #=> 173823271649325368927
  61. say '=' x 80;
  62. # Works even with larger numbers
  63. say carmichael_factorization(89279013890805987845789287109721287627454944588023686038653206281186298337098760877273881); #=> 245960883729518060519840003581
  64. say carmichael_factorization(131754870930495356465893439278330079857810087607720627102926770417203664110488210785830750894645370240615968198960237761, 4); #=> 245960883729518060519840003581
  65. #>>>