pollard_rho_exp_factorization.pl 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/perl
  2. # Pollard's rho integer factorization algorithm.
  3. # This version uses the polynomial:
  4. # f(x) = x^e + 2*e - 1
  5. # where e = lcm(1..B), for a small bound B.
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
  8. use 5.020;
  9. use strict;
  10. use warnings;
  11. use experimental qw(signatures);
  12. use Math::GMPz;
  13. use Math::Prime::Util::GMP qw(consecutive_integer_lcm logint);
  14. sub rho_exp_factor ($n, $max_iter = 5000) {
  15. my $B = logint($n, 5)**2;
  16. my $e = Math::GMPz::Rmpz_init_set_str(consecutive_integer_lcm($B), 10);
  17. my $c = 2*$e - 1;
  18. if (length("$n") <= 12) {
  19. $e = Math::GMPz->new(2);
  20. }
  21. my $x = Math::GMPz::Rmpz_init_set_ui(1);
  22. my $y = Math::GMPz::Rmpz_init();
  23. my $g = Math::GMPz::Rmpz_init();
  24. Math::GMPz::Rmpz_powm($x, $x, $e, $n);
  25. Math::GMPz::Rmpz_add($x, $x, $c);
  26. Math::GMPz::Rmpz_mod($x, $x, $n);
  27. Math::GMPz::Rmpz_powm($y, $x, $e, $n);
  28. Math::GMPz::Rmpz_add($y, $y, $c);
  29. Math::GMPz::Rmpz_mod($y, $y, $n);
  30. for (1 .. $max_iter) {
  31. Math::GMPz::Rmpz_powm($x, $x, $e, $n);
  32. Math::GMPz::Rmpz_add($x, $x, $c);
  33. Math::GMPz::Rmpz_mod($x, $x, $n);
  34. Math::GMPz::Rmpz_powm($y, $y, $e, $n);
  35. Math::GMPz::Rmpz_add($y, $y, $c);
  36. Math::GMPz::Rmpz_mod($y, $y, $n);
  37. Math::GMPz::Rmpz_powm($y, $y, $e, $n);
  38. Math::GMPz::Rmpz_add($y, $y, $c);
  39. Math::GMPz::Rmpz_mod($y, $y, $n);
  40. Math::GMPz::Rmpz_sub($g, $x, $y);
  41. Math::GMPz::Rmpz_gcd($g, $g, $n);
  42. if (Math::GMPz::Rmpz_cmp_ui($g, 1) != 0) {
  43. return undef if ($g == $n);
  44. return $g;
  45. }
  46. }
  47. return $n;
  48. }
  49. my @nums = qw(
  50. 314159265358979323 350011490889402191 2954624367769580651
  51. 7167393334524676153 10033529742475370477 20135752530477192241
  52. 21316902507352787201 2559469924891866771047 63469917720180180377579
  53. );
  54. @nums = map { Math::GMPz->new($_) } @nums;
  55. foreach my $n (@nums) {
  56. say "rho_exp_factor($n) = ", rho_exp_factor($n);
  57. }
  58. __END__
  59. rho_exp_factor(314159265358979323) = 990371647
  60. rho_exp_factor(350011490889402191) = 692953181
  61. rho_exp_factor(2954624367769580651) = 490066931
  62. rho_exp_factor(7167393334524676153) = 4721424559
  63. rho_exp_factor(10033529742475370477) = 1412164441
  64. rho_exp_factor(20135752530477192241) = 5907768749
  65. rho_exp_factor(21316902507352787201) = 3055371353
  66. rho_exp_factor(2559469924891866771047) = 266349879973
  67. rho_exp_factor(63469917720180180377579) = 126115748167