@@ -230,10 +230,9 @@ isprime(n::Int128) = n < 2 ? false :
230
230
231
231
232
232
# Trial division of small (< 2^16) precomputed primes +
233
- # Pollard rho's algorithm with Richard P. Brent optimizations
233
+ # Lenstra elliptic curve algorithm
234
234
# 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
237
236
#
238
237
function factor! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
239
238
# check for special cases
@@ -257,18 +256,17 @@ function factor!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Integer}
257
256
for p in PRIMES
258
257
p > nsqrt && break
259
258
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
263
260
h[p] = get (h, p, 0 ) + 1
264
- n = div (n, p)
261
+ n, r = divrem (n, p)
262
+ r != 0 && break
265
263
end
266
264
n == 1 && return h
267
265
nsqrt = isqrt (n)
268
266
end
269
267
end
270
268
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)
272
270
end
273
271
274
272
@@ -386,52 +384,84 @@ julia> radical(2*2*3)
386
384
"""
387
385
radical (n) = prod (factor (Set, n))
388
386
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
401
394
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)
407
419
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
416
447
end
417
- G = gcd (q, n)
418
- k += m
419
448
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
433
461
end
462
+ x, y = xn, yn
434
463
end
464
+ return T (1 )
435
465
end
436
466
437
467
"""
0 commit comments