fermat_factorization_method.pl 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 16 March 2018
  4. # https://github.com/trizen
  5. # A simple implementation of Fermat's factorization method.
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Fermat%27s_factorization_method
  8. use 5.020;
  9. use strict;
  10. use warnings;
  11. use experimental qw(signatures);
  12. use ntheory qw(is_prime vecprod);
  13. use Math::AnyNum qw(:overload isqrt is_square valuation);
  14. sub fermat_factorization ($n) {
  15. # Check for primes and negative numbers
  16. return () if ($n <= 1);
  17. return ($n) if is_prime($n);
  18. # Check for divisibility by 2
  19. if (!($n & 1)) {
  20. my $v = valuation($n, 2);
  21. return ((2) x $v, __SUB__->($n >> $v));
  22. }
  23. my $q = 2 * isqrt($n);
  24. while (!is_square($q * $q - 4 * $n)) {
  25. $q += 2;
  26. }
  27. my $p = ($q + isqrt($q * $q - 4 * $n)) >> 1;
  28. return sort { $a <=> $b } (
  29. __SUB__->($p),
  30. __SUB__->($n / $p),
  31. );
  32. }
  33. foreach my $n (160587846247027, 5040, 65127835124, 6469693230) {
  34. my @f = fermat_factorization($n);
  35. say join(' * ', @f), " = $n";
  36. die 'error' if vecprod(@f) != $n;
  37. }