@@ -320,11 +320,10 @@ Base.isempty(f::FactorIterator) = f.n == 1
320
320
# Uses a variety of algorithms depending on the size of n to find a factor.
321
321
# https://en.algorithmica.org/hpc/algorithms/factorization
322
322
# 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
325
325
# 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
328
327
#
329
328
330
329
"""
@@ -387,8 +386,20 @@ function iterate(f::FactorIterator{T}, state=(f.n, T(3))) where T
387
386
if n <= 2 ^ 32 || isprime (n)
388
387
return (n, 1 ), (T (1 ), n)
389
388
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
+
390
401
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))
392
403
num_p = 0
393
404
while true
394
405
q, r = divrem (n, p)
@@ -520,55 +531,65 @@ julia> radical(2*2*3)
520
531
"""
521
532
radical (n) = n== 1 ? one (n) : prod (p for (p, num_p) in eachfactor (n))
522
533
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)
553
547
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)
561
548
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
568
576
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
570
589
end
590
+ x, y = xn, yn
571
591
end
592
+ return T (1 )
572
593
end
573
594
574
595
"""
@@ -646,7 +667,7 @@ given by `f`. This method may be preferable to [`totient(::Integer)`](@ref)
646
667
when the factorization can be reused for other purposes.
647
668
"""
648
669
function totient (f:: Factorization{T} ) where T <: Integer
649
- if iszero ( sign ( f))
670
+ if ! isempty (f) && first ( first ( f)) == 0
650
671
throw (ArgumentError (" ϕ(0) is not defined" ))
651
672
end
652
673
result = one (T)
@@ -665,16 +686,8 @@ positive integers less than or equal to ``n`` that are relatively prime to
665
686
The totient function of `n` when `n` is negative is defined to be
666
687
`totient(abs(n))`.
667
688
"""
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)))
678
691
end
679
692
680
693
# 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} =
964
977
965
978
"""
966
979
divisors(n::Integer) -> Vector
967
-
968
980
Return a vector with the positive divisors of `n`.
969
-
970
981
For a nonzero integer `n` with prime factorization `n = p₁^k₁ ⋯ pₘ^kₘ`, `divisors(n)`
971
982
returns a vector of length (k₁ + 1)⋯(kₘ + 1) containing the divisors of `n` in
972
983
lexicographic (rather than numerical) order.
973
-
974
984
`divisors(-n)` is equivalent to `divisors(n)`.
975
-
976
985
For convenience, `divisors(0)` returns `[]`.
977
-
978
986
# Example
979
-
980
987
```jldoctest; filter = r"(\\ s+#.*)?"
981
988
julia> divisors(60)
982
989
12-element Vector{Int64}:
@@ -992,14 +999,12 @@ julia> divisors(60)
992
999
15 # 5 * 3
993
1000
30 # 5 * 3 * 2
994
1001
60 # 5 * 3 * 2 * 2
995
-
996
1002
julia> divisors(-10)
997
1003
4-element Vector{Int64}:
998
1004
1
999
1005
2
1000
1006
5
1001
1007
10
1002
-
1003
1008
julia> divisors(0)
1004
1009
Int64[]
1005
1010
```
@@ -1017,7 +1022,6 @@ end
1017
1022
1018
1023
"""
1019
1024
divisors(f::Factorization) -> Vector
1020
-
1021
1025
Return a vector with the positive divisors of the number whose factorization is `f`.
1022
1026
Divisors are sorted lexicographically, rather than numerically.
1023
1027
"""
0 commit comments