From d52bb1ffee5b64206a26323f7475c5aaf4a5046d Mon Sep 17 00:00:00 2001 From: trizen Date: Thu, 7 Jan 2021 17:30:08 +0200 Subject: [PATCH] - Added the Number `flt_factor(n, tries=1e4)` method. Tries to find a factor of `n`, using a new factorization method, inspired by Fermat's Little Theorem (FLT). The method is particularily effective for numbers that have factors closed to each other, or have a factor `k` for which `znorder(2,k)` is small. Example: say flt_factor(1759590140239532167230871849749630652332178307219845847129) #=> [12072684186515582507, 145749703467343411357142937615495959947] say flt_factor(28168370236334094367936640078057043313881469151722840306493) #=> [30426633744568826749, 925780041026134419587821276142742168257] ...taking 0.007s in total. --- lib/Sidef/Types/Number/Number.pm | 50 +++++++++++++++++++++++++++++++ lib/Sidef/Types/Number/Number.pod | 8 +++++ 2 files changed, 58 insertions(+) diff --git a/lib/Sidef/Types/Number/Number.pm b/lib/Sidef/Types/Number/Number.pm index 9ebd35f8a..1ac97eed6 100644 --- a/lib/Sidef/Types/Number/Number.pm +++ b/lib/Sidef/Types/Number/Number.pm @@ -12975,6 +12975,56 @@ package Sidef::Types::Number::Number { Sidef::Types::Array::Array->new([bless(\$n)]); } + # "Fermat's Little Theorem" factorization method + sub flt_factor { + my ($n, $k) = @_; + _valid(\$k) if defined($k); + + $n = _any2mpz($$n) // return Sidef::Types::Array::Array->new(); + + if (defined($k)) { + $k = _any2ui($$k) // 1e4; + } + else { + $k = 1e4; + } + + state $z = Math::GMPz::Rmpz_init_nobless(); + state $t = Math::GMPz::Rmpz_init_nobless(); + + Math::GMPz::Rmpz_powm($z, $TWO, $n, $n); + + # Cannot factor Fermat pseudoprimes + if (Math::GMPz::Rmpz_cmp_ui($z, 2) == 0) { + return Sidef::Types::Array::Array->new([bless \$n]); + } + + for (my $j = 1 ; $j <= $k ; $j += 2) { + + Math::GMPz::Rmpz_powm_ui($t, $TWO, $j, $n); + Math::GMPz::Rmpz_sub($t, $z, $t); + Math::GMPz::Rmpz_gcd($t, $t, $n); + + if (Math::GMPz::Rmpz_cmp_ui($t, 1) > 0) { + + if (Math::GMPz::Rmpz_cmp($t, $n) == 0) { + return Sidef::Types::Array::Array->new([bless \$n]); + } + + my $x = Math::GMPz::Rmpz_init(); + my $y = Math::GMPz::Rmpz_init(); + + Math::GMPz::Rmpz_set($y, $t); + Math::GMPz::Rmpz_divexact($x, $n, $t); + + my @f = map { bless \$_ } sort { Math::GMPz::Rmpz_cmp($a, $b) } ($x, $y); + return Sidef::Types::Array::Array->new(\@f); + } + } + + Sidef::Types::Array::Array->new([bless(\$n)]); + } + sub squfof_factor { my ($n, $k) = @_; _valid(\$k) if defined($k); diff --git a/lib/Sidef/Types/Number/Number.pod b/lib/Sidef/Types/Number/Number.pod index 76b425efd..4b1cfc0df 100644 --- a/lib/Sidef/Types/Number/Number.pod +++ b/lib/Sidef/Types/Number/Number.pod @@ -1902,6 +1902,14 @@ Return the =cut +=head2 flt_factor + +Number.flt_factor() -> I + +Return the + +=cut + =head2 gcd Number.gcd() -> I