@@ -9,7 +9,7 @@ using Base: BitSigned
9
9
using Base. Checked: checked_neg
10
10
using IntegerMathUtils
11
11
12
- export isprime, primes, primesmask, factor, ismersenneprime, isrieselprime,
12
+ export isprime, primes, primesmask, factor, eachfactor, ismersenneprime, isrieselprime,
13
13
nextprime, nextprimes, prevprime, prevprimes, prime, prodfactors, radical, totient
14
14
15
15
include (" factorization.jl" )
148
148
149
149
const N_SMALL_FACTORS = 2 ^ 16
150
150
const _MIN_FACTOR = UInt8 .(_generate_min_factors (N_SMALL_FACTORS))
151
- # _min_factor(n) = 1 if n is prime, otherwise the minimum factor of n
152
- _min_factor (n) = _MIN_FACTOR[n>> 1 ]
151
+ # _min_factor(n) = the minimum factor of n for odd n, if 1<n<N_SMALL_FACTORS
152
+ function _min_factor (n:: T ) where T<: Integer
153
+ m = _MIN_FACTOR[n>> 1 ]
154
+ return m== 1 ? n : T (m)
155
+ end
153
156
154
157
"""
155
158
isprime(n::Integer) -> Bool
@@ -168,7 +171,7 @@ function isprime(n::Integer)
168
171
n < 2 && return false
169
172
trailing_zeros (n) > 0 && return n== 2
170
173
if n < N_SMALL_FACTORS
171
- return _min_factor (n) == 1
174
+ return _min_factor (n) == n
172
175
end
173
176
for m in (3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 )
174
177
n % m == 0 && return false
@@ -251,65 +254,93 @@ isprime(n::UInt128) =
251
254
isprime (n:: Int128 ) = n < 2 ? false :
252
255
n ≤ typemax (UInt64) ? isprime (UInt64 (n)) : isprime (BigInt (n))
253
256
254
- # Cache of small factors for tiny numbers (n < 2^16)
257
+ struct FactorIterator{T<: Integer }
258
+ n:: T
259
+ FactorIterator (n:: T ) where {T} = new {T} (n)
260
+ end
261
+
262
+ IteratorSize (:: Type{<:FactorIterator} ) = Base. SizeUnknown ()
263
+ IteratorEltype (:: Type{<:FactorIterator} ) = Base. HasEltype ()
264
+ eltype (:: Type{FactorIterator{T}} ) where {T} = T
265
+ Base. isempty (f:: FactorIterator ) = f. n == 1
266
+
267
+ # Iterates over the factors of n in an arbitrary order
268
+ # Uses a variety of algorithms depending on the size of n to find a factor.
269
+ # https://en.algorithmica.org/hpc/algorithms/factorization
270
+ # Cache of small factors for small numbers (n < 2^16)
255
271
# Trial division of small (< 2^16) precomputed primes
256
272
# Pollard rho's algorithm with Richard P. Brent optimizations
257
273
# https://en.wikipedia.org/wiki/Trial_division
258
274
# https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
259
275
# http://maths-people.anu.edu.au/~brent/pub/pub051.html
260
276
#
261
- function factor! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
262
- # check for special cases
263
- if n < 0
264
- h[- 1 ] = 1 - h[- 1 ]
265
- if isa (n, BitSigned) && n == typemin (T)
266
- h[2 ] += 8 * sizeof (T) - 1
267
- return h
268
- else
269
- return factor! (checked_neg (n), h)
277
+ eachfactor (n:: Integer ) = FactorIterator (n)
278
+
279
+ # state[1] is the current number to factor (this decreases when factors are found)
280
+ # state[2] is the prime to start trial division with.
281
+ function iterate (f:: FactorIterator{T} , state= (f. n, T (3 ))) where T
282
+ n, p:: T = state
283
+ if n <= p
284
+ n == 1 && return nothing
285
+ if n < 0
286
+ # if n is typemin, we can't negate it properly
287
+ # instead we set p=n which we can detect here.
288
+ if isa (n, BitSigned) && n == typemin (T)
289
+ if n != p
290
+ return (T (- 1 ), 1 ), (n, n)
291
+ end
292
+ return (T (2 ), 8 * sizeof (T) - 1 ), T .((1 , 1 ))
293
+ end
294
+ return (T (- 1 ), 1 ), (- n, p)
270
295
end
271
- elseif n == 0
272
- h[n] = 1
273
- return h
274
- elseif trailing_zeros (n) > 0
275
- tz = trailing_zeros (n)
276
- increment! (h, tz, 2 )
277
- n >>= tz
296
+ n == 0 && return (T (n), 1 ), (T (1 ), p)
278
297
end
298
+ tz = trailing_zeros (n)
299
+ tz> 0 && return (T (2 ), tz), (n >> tz, p)
279
300
if n <= N_SMALL_FACTORS
301
+ p = _min_factor (n)
302
+ num_p = 1
280
303
while true
281
- n == 1 && return h
282
- if _min_factor (n)== 1
283
- return increment! (h, 1 , n)
284
- else
285
- increment! (h, 1 , _min_factor (n))
286
- n = div (n, _min_factor (n))
287
- end
304
+ n = div (n, p)
305
+ n == 1 && break
306
+ _min_factor (n) == p || break
307
+ num_p += 1
288
308
end
309
+ return (p, num_p), (n, p)
289
310
elseif isprime (n)
290
- return increment! (h , 1 , n)
311
+ return (n , 1 ), ( T ( 1 ) , n)
291
312
end
292
- local p:: T
293
- for p in 3 : 2 : N_SMALL_FACTORS
294
- _min_factor (p) == 1 || continue
313
+ for p in p: 2 : N_SMALL_FACTORS
314
+ isprime (p) || continue
295
315
num_p = 0
296
316
while true
297
317
q, r = divrem (n, T (p)) # T(p) so julia <1.9 uses fast divrem for `BigInt`
298
318
r == 0 || break
299
319
num_p += 1
300
320
n = q
301
321
end
302
- # h[p] += num_p (about 2x faster, but the speed only matters for small numbers)
303
322
if num_p > 0
304
- increment! (h, num_p, p)
305
- # if n is small, then recursing will hit the fast path.
306
- n < N_SMALL_FACTORS && return factor! (n, h)
323
+ return (p, num_p), (n, p)
307
324
end
308
325
p* p > n && break
309
326
end
310
- n == 1 && return h
311
- isprime (n) && return increment! (h, 1 , n)
312
- T <: BigInt || widemul (n - 1 , n - 1 ) ≤ typemax (n) ? pollardfactors! (n, h) : pollardfactors! (widen (n), h)
327
+ isprime (n) && (n, 1 ), (T (1 ), n)
328
+ should_widen = T <: BigInt || widemul (n - 1 , n - 1 ) ≤ typemax (n)
329
+ p = should_widen ? pollardfactor (n) : pollardfactor (widen (n))
330
+ num_p = 0
331
+ while true
332
+ q, r = divrem (n, p)
333
+ r != 0 && return (p, num_p), (n, p)
334
+ num_p += 1
335
+ n = q
336
+ end
337
+ end
338
+
339
+ function factor! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
340
+ for (p, num_p) in eachfactor (n)
341
+ increment! (h, num_p, p)
342
+ end
343
+ return h
313
344
end
314
345
315
346
@@ -425,15 +456,15 @@ julia> radical(2*2*3)
425
456
6
426
457
```
427
458
"""
428
- radical (n) = prod (factor (Set, n))
459
+ radical (n) = n == 1 ? one (n) : prod (p for (p, num_p) in eachfactor ( n))
429
460
430
- function pollardfactors! (n:: T , h :: AbstractDict{K,Int} ) where {T<: Integer ,K <: Integer }
461
+ function pollardfactor (n:: T ) where {T<: Integer }
431
462
while true
432
463
c:: T = rand (1 : (n - 1 ))
433
464
G:: T = 1
434
- r:: K = 1
465
+ r:: T = 1
435
466
y:: T = rand (0 : (n - 1 ))
436
- m:: K = 100
467
+ m:: T = 100
437
468
ys:: T = 0
438
469
q:: T = 1
439
470
x:: T = 0
@@ -446,7 +477,7 @@ function pollardfactors!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Inte
446
477
y = y^ 2 % n
447
478
y = (y + c) % n
448
479
end
449
- k:: K = 0
480
+ k:: T = 0
450
481
G = 1
451
482
while k < r && G == 1
452
483
ys = y
@@ -467,10 +498,13 @@ function pollardfactors!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Inte
467
498
G = gcd (x > ys ? x - ys : ys - x, n)
468
499
end
469
500
if G != n
470
- isprime (G) ? h[G] = get (h, G, 0 ) + 1 : pollardfactors! (G, h)
471
501
G2 = div (n,G)
472
- isprime (G2) ? h[G2] = get (h, G2, 0 ) + 1 : pollardfactors! (G2, h)
473
- return h
502
+ f = min (G, G2)
503
+ _gcd = gcd (G, G2)
504
+ if _gcd != 1
505
+ f = _gcd
506
+ end
507
+ return isprime (f) ? f : pollardfactor (f)
474
508
end
475
509
end
476
510
end
@@ -569,8 +603,16 @@ positive integers less than or equal to ``n`` that are relatively prime to
569
603
The totient function of `n` when `n` is negative is defined to be
570
604
`totient(abs(n))`.
571
605
"""
572
- function totient (n:: Integer )
573
- totient (factor (abs (n)))
606
+ function totient (n:: T ) where T<: Integer
607
+ n = abs (n)
608
+ if n == 0
609
+ throw (ArgumentError (" ϕ(0) is not defined" ))
610
+ end
611
+ result = one (T)
612
+ for (p, k) in eachfactor (n)
613
+ result *= p^ (k- 1 ) * (p - 1 )
614
+ end
615
+ result
574
616
end
575
617
576
618
# add: checked add (when makes sense), result of same type as first argument
0 commit comments