@@ -320,11 +320,10 @@ Base.isempty(f::FactorIterator) = f.n == 1
320320# Uses a variety of algorithms depending on the size of n to find a factor.
321321# https://en.algorithmica.org/hpc/algorithms/factorization
322322# Cache of small factors for small numbers (n < 2^16)
323- # Trial division of small (< 2^16) precomputed primes
324- # Pollard rho's algorithm with Richard P. Brent optimizations
323+ # Trial division of small (< 2^16) precomputed primes and
324+ # Lenstra elliptic curve algorithm
325325# https://en.wikipedia.org/wiki/Trial_division
326- # https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
327- # http://maths-people.anu.edu.au/~brent/pub/pub051.html
326+ # https://en.wikipedia.org/wiki/Lenstra_elliptic-curve_factorization
328327#
329328
330329"""
@@ -387,8 +386,20 @@ function iterate(f::FactorIterator{T}, state=(f.n, T(3))) where T
387386 if n <= 2 ^ 32 || isprime (n)
388387 return (n, 1 ), (T (1 ), n)
389388 end
389+ # check for n=root^r
390+ r = cld (ndigits (n, base= 2 ), ndigits (N_SMALL_FACTORS, base= 2 ))
391+ root = iroot (n, r)
392+ while r >= 2
393+ if root^ r == n
394+ isprime (root) && return (root, r), (n, root+ 2 )
395+
396+ end
397+ r -= 1
398+ root = iroot (n, r)
399+ end
400+
390401 should_widen = T <: BigInt || widemul (n - 1 , n - 1 ) ≤ typemax (n)
391- p = should_widen ? pollardfactor (n) : pollardfactor (widen (n))
402+ p = should_widen ? lenstrafactor (n) : lenstrafactor (widen (n))
392403 num_p = 0
393404 while true
394405 q, r = divrem (n, p)
@@ -520,55 +531,65 @@ julia> radical(2*2*3)
520531"""
521532radical (n) = n== 1 ? one (n) : prod (p for (p, num_p) in eachfactor (n))
522533
523- function pollardfactor (n:: T ) where {T<: Integer }
524- while true
525- c:: T = rand (1 : (n - 1 ))
526- G:: T = 1
527- r:: T = 1
528- y:: T = rand (0 : (n - 1 ))
529- m:: T = 100
530- ys:: T = 0
531- q:: T = 1
532- x:: T = 0
533- while c == n - 2
534- c = rand (1 : (n - 1 ))
535- end
536- while G == 1
537- x = y
538- for i in 1 : r
539- y = y^ 2 % n
540- y = (y + c) % n
541- end
542- k:: T = 0
543- G = 1
544- while k < r && G == 1
545- ys = y
546- for i in 1 : (m > (r - k) ? (r - k) : m)
547- y = y^ 2 % n
548- y = (y + c) % n
549- q = (q * (x > y ? x - y : y - x)) % n
550- end
551- G = gcd (q, n)
552- k += m
534+ function lenstrafactor (n:: T ) where {T<: Integer }
535+ # bounds and runs per bound taken from
536+ # https://www.rieselprime.de/ziki/Elliptic_curve_method
537+ B1s = Int[2e3 , 11e3 , 5e4 , 25e4 , 1e6 , 3e6 , 11e6 ,
538+ 43e6 , 11e7 , 26e7 , 85e7 , 29e8 , 76e8 , 25e9 ]
539+ runs = Int[25 , 90 , 300 , 700 , 1800 , 5100 , 1800 , 10600 ,
540+ 19300 , 49000 , 124000 , 210000 , 340000 , 10 ^ 6 , 10 ^ 7 ]
541+ for (B1, run) in zip (B1s, runs)
542+ small_primes = primes (B1)
543+ for a in - run: run
544+ res = lenstra_get_factor (n, a, small_primes, B1)
545+ if res != 1
546+ return isprime (res) ? res : lenstrafactor (res)
553547 end
554- r *= 2
555- end
556- G == n && (G = 1 )
557- while G == 1
558- ys = ys^ 2 % n
559- ys = (ys + c) % n
560- G = gcd (x > ys ? x - ys : ys - x, n)
561548 end
562- if G != n
563- G2 = div (n,G)
564- f = min (G, G2)
565- _gcd = gcd (G, G2)
566- if _gcd != 1
567- f = _gcd
549+ end
550+ throw (ArgumentError (" This number is too big to be factored with this algorith effectively" ))
551+ end
552+
553+ function lenstra_get_factor (N:: T , a, small_primes, plimit) where T <: Integer
554+ x, y = T (0 ), T (1 )
555+ for B in small_primes
556+ t = B^ trunc (Int64, log (B, plimit))
557+ xn, yn = T (0 ), T (0 )
558+ sx, sy = x, y
559+
560+ first = true
561+ while t > 0
562+ if isodd (t)
563+ if first
564+ xn, yn = sx, sy
565+ first = false
566+ else
567+ g, u, _ = gcdx (sx- xn, N)
568+ g > 1 && (g == N ? break : return g)
569+ u += N
570+ L = (u* (sy- yn)) % N
571+ xs = (L* L - xn - sx) % N
572+
573+ yn = (L* (xn - xs) - yn) % N
574+ xn = xs
575+ end
568576 end
569- return isprime (f) ? f : pollardfactor (f)
577+ g, u, _ = gcdx (2 * sy, N)
578+ g > 1 && (g == N ? break : return g)
579+ u += N
580+
581+ L = (u* (3 * sx* sx + a)) % N
582+ x2 = (L* L - 2 * sx) % N
583+
584+ sy = (L* (sx - x2) - sy) % N
585+ sx = x2
586+
587+ sy == 0 && return T (1 )
588+ t >>= 1
570589 end
590+ x, y = xn, yn
571591 end
592+ return T (1 )
572593end
573594
574595"""
@@ -646,7 +667,7 @@ given by `f`. This method may be preferable to [`totient(::Integer)`](@ref)
646667when the factorization can be reused for other purposes.
647668"""
648669function totient (f:: Factorization{T} ) where T <: Integer
649- if iszero ( sign ( f))
670+ if ! isempty (f) && first ( first ( f)) == 0
650671 throw (ArgumentError (" ϕ(0) is not defined" ))
651672 end
652673 result = one (T)
@@ -665,16 +686,8 @@ positive integers less than or equal to ``n`` that are relatively prime to
665686The totient function of `n` when `n` is negative is defined to be
666687`totient(abs(n))`.
667688"""
668- function totient (n:: T ) where T<: Integer
669- n = abs (n)
670- if n == 0
671- throw (ArgumentError (" ϕ(0) is not defined" ))
672- end
673- result = one (T)
674- for (p, k) in eachfactor (n)
675- result *= p^ (k- 1 ) * (p - 1 )
676- end
677- result
689+ function totient (n:: Integer )
690+ totient (factor (abs (n)))
678691end
679692
680693# add: checked add (when makes sense), result of same type as first argument
@@ -964,19 +977,13 @@ prevprimes(start::T, n::Integer) where {T<:Integer} =
964977
965978"""
966979 divisors(n::Integer) -> Vector
967-
968980Return a vector with the positive divisors of `n`.
969-
970981For a nonzero integer `n` with prime factorization `n = p₁^k₁ ⋯ pₘ^kₘ`, `divisors(n)`
971982returns a vector of length (k₁ + 1)⋯(kₘ + 1) containing the divisors of `n` in
972983lexicographic (rather than numerical) order.
973-
974984`divisors(-n)` is equivalent to `divisors(n)`.
975-
976985For convenience, `divisors(0)` returns `[]`.
977-
978986# Example
979-
980987```jldoctest; filter = r"(\\ s+#.*)?"
981988julia> divisors(60)
98298912-element Vector{Int64}:
@@ -992,14 +999,12 @@ julia> divisors(60)
992999 15 # 5 * 3
9931000 30 # 5 * 3 * 2
9941001 60 # 5 * 3 * 2 * 2
995-
9961002julia> divisors(-10)
99710034-element Vector{Int64}:
9981004 1
9991005 2
10001006 5
10011007 10
1002-
10031008julia> divisors(0)
10041009Int64[]
10051010```
@@ -1017,7 +1022,6 @@ end
10171022
10181023"""
10191024 divisors(f::Factorization) -> Vector
1020-
10211025Return a vector with the positive divisors of the number whose factorization is `f`.
10221026Divisors are sorted lexicographically, rather than numerically.
10231027"""
0 commit comments