@@ -230,10 +230,9 @@ isprime(n::Int128) = n < 2 ? false :
230230
231231
232232# Trial division of small (< 2^16) precomputed primes +
233- # Pollard rho's algorithm with Richard P. Brent optimizations
233+ # Lenstra elliptic curve algorithm
234234# https://en.wikipedia.org/wiki/Trial_division
235- # https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
236- # http://maths-people.anu.edu.au/~brent/pub/pub051.html
235+ # https://en.wikipedia.org/wiki/Lenstra_elliptic-curve_factorization
237236#
238237function factor! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
239238 # check for special cases
@@ -257,18 +256,17 @@ function factor!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Integer}
257256 for p in PRIMES
258257 p > nsqrt && break
259258 if n % p == 0
260- h[p] = get (h, p, 0 ) + 1
261- n = div (n, p)
262- while n % p == 0
259+ while true
263260 h[p] = get (h, p, 0 ) + 1
264- n = div (n, p)
261+ n, r = divrem (n, p)
262+ r != 0 && break
265263 end
266264 n == 1 && return h
267265 nsqrt = isqrt (n)
268266 end
269267 end
270268 isprime (n) && (h[n]= 1 ; return h)
271- T <: BigInt || widemul (n - 1 , n - 1 ) ≤ typemax (n) ? pollardfactors! (n, h) : pollardfactors ! (widen (n), h)
269+ lenstrafactors ! (widen (n), h)
272270end
273271
274272
@@ -386,52 +384,84 @@ julia> radical(2*2*3)
386384"""
387385radical (n) = prod (factor (Set, n))
388386
389- function pollardfactors! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
390- while true
391- c:: T = rand (1 : (n - 1 ))
392- G:: T = 1
393- r:: K = 1
394- y:: T = rand (0 : (n - 1 ))
395- m:: K = 100
396- ys:: T = 0
397- q:: T = 1
398- x:: T = 0
399- while c == n - 2
400- c = rand (1 : (n - 1 ))
387+ function primepowerfactor! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
388+ r = ceil (Int, inv (log (n, Primes. PRIMES[end ])))+ 1
389+ root = inthroot (n, r)
390+ while r >= 2
391+ if root^ r == n && isprime (root)
392+ h[root] = get (h, root, 0 ) + r
393+ return true
401394 end
402- while G == 1
403- x = y
404- for i in 1 : r
405- y = y^ 2 % n
406- y = (y + c) % n
395+ r -= 1
396+ root = inthroot (n, r)
397+ end
398+ return false
399+ end
400+
401+ function lenstrafactors! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
402+ isprime (n) && (h[n] = get (h, n, 0 )+ 1 ; return h)
403+ primepowerfactor! (n:: T , h) && return h
404+ # bounds and runs per bound taken from
405+ # https://www.rieselprime.de/ziki/Elliptic_curve_method
406+ B1s = Int[2e3 , 11e3 , 5e4 , 25e4 , 1e6 , 3e6 , 11e6 ,
407+ 43e6 , 11e7 , 26e7 , 85e7 , 29e8 , 76e8 , 25e9 ]
408+ runs = (74 , 221 , 453 , 984 , 2541 , 4949 , 8266 , 20158 ,
409+ 47173 , 77666 , 42057 , 69471 , 102212 , 188056 , 265557 )
410+ for (B1, run) in zip (B1s, runs)
411+ small_primes = primes (B1)
412+ for a in - run: run
413+ res = lenstra_get_factor (n, a, small_primes, B1)
414+ if res != 1
415+ isprime (res) ? h[res] = get (h, res, 0 ) + 1 : lenstrafactors! (res, h)
416+ n = div (n,res)
417+ primepowerfactor! (n:: T , h) && return h
418+ isprime (n) && (h[n] = get (h, n, 0 ) + 1 ; return h)
407419 end
408- k:: K = 0
409- G = 1
410- while k < r && G == 1
411- ys = y
412- for i in 1 : (m > (r - k) ? (r - k) : m)
413- y = y^ 2 % n
414- y = (y + c) % n
415- q = (q * (x > y ? x - y : y - x)) % n
420+ end
421+ end
422+ throw (ArgumentError (" This number is too big to be factored with this algorith effectively" ))
423+ end
424+
425+ function lenstra_get_factor (N:: T , a, small_primes, plimit) where T <: Integer
426+ x, y = T (0 ), T (1 )
427+ for B in small_primes
428+ t = B^ trunc (Int64, log (B, plimit))
429+ xn, yn = T (0 ), T (0 )
430+ sx, sy = x, y
431+
432+ first = true
433+ while t > 0
434+ if isodd (t)
435+ if first
436+ xn, yn = sx, sy
437+ first = false
438+ else
439+ g, u, _ = gcdx (sx- xn, N)
440+ g > 1 && (g == N ? break : return g)
441+ u += N
442+ L = (u* (sy- yn)) % N
443+ xs = (L* L - xn - sx) % N
444+
445+ yn = (L* (xn - xs) - yn) % N
446+ xn = xs
416447 end
417- G = gcd (q, n)
418- k += m
419448 end
420- r *= 2
421- end
422- G == n && (G = 1 )
423- while G == 1
424- ys = ys^ 2 % n
425- ys = (ys + c) % n
426- G = gcd (x > ys ? x - ys : ys - x, n)
427- end
428- if G != n
429- isprime (G) ? h[G] = get (h, G, 0 ) + 1 : pollardfactors! (G, h)
430- G2 = div (n,G)
431- isprime (G2) ? h[G2] = get (h, G2, 0 ) + 1 : pollardfactors! (G2, h)
432- return h
449+ g, u, _ = gcdx (2 * sy, N)
450+ g > 1 && (g == N ? break : return g)
451+ u += N
452+
453+ L = (u* (3 * sx* sx + a)) % N
454+ x2 = (L* L - 2 * sx) % N
455+
456+ sy = (L* (sx - x2) - sy) % N
457+ sx = x2
458+
459+ sy == 0 && return T (1 )
460+ t >>= 1
433461 end
462+ x, y = xn, yn
434463 end
464+ return T (1 )
435465end
436466
437467"""
0 commit comments