@@ -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
190
193
191
194
"""
192
195
isprime(x::BigInt, [reps = 25]) -> Bool
193
-
194
196
Probabilistic primality test. Returns `true` if `x` is prime with high probability (pseudoprime);
195
197
and `false` if `x` is composite (not prime). The false positive rate is about `0.25^reps`.
196
198
`reps = 25` is considered safe for cryptographic applications (Knuth, Seminumerical Algorithms).
197
-
198
199
```julia
199
200
julia> isprime(big(3))
200
201
true
@@ -251,65 +252,103 @@ isprime(n::UInt128) =
251
252
isprime (n:: Int128 ) = n < 2 ? false :
252
253
n ≤ typemax (UInt64) ? isprime (UInt64 (n)) : isprime (BigInt (n))
253
254
254
- # Cache of small factors for tiny numbers (n < 2^16)
255
+ struct FactorIterator{T<: Integer }
256
+ n:: T
257
+ FactorIterator (n:: T ) where {T} = new {T} (n)
258
+ end
259
+
260
+ IteratorSize (:: Type{<:FactorIterator} ) = Base. SizeUnknown ()
261
+ IteratorEltype (:: Type{<:FactorIterator} ) = Base. HasEltype ()
262
+ eltype (:: Type{FactorIterator{T}} ) where {T} = Tuple{T, Int}
263
+ Base. isempty (f:: FactorIterator ) = f. n == 1
264
+
265
+ # Iterates over the factors of n in an arbitrary order
266
+ # Uses a variety of algorithms depending on the size of n to find a factor.
267
+ # https://en.algorithmica.org/hpc/algorithms/factorization
268
+ # Cache of small factors for small numbers (n < 2^16)
255
269
# Trial division of small (< 2^16) precomputed primes
256
270
# Pollard rho's algorithm with Richard P. Brent optimizations
257
271
# https://en.wikipedia.org/wiki/Trial_division
258
272
# https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
259
273
# http://maths-people.anu.edu.au/~brent/pub/pub051.html
260
274
#
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)
275
+
276
+ """
277
+ eachfactor(n::Integer)->FactorIterator
278
+ Returns a lazy iterator of factors of `n` in `(factor, multiplicity)` pairs.
279
+ This can be very useful for computing multiplicitive functions since for small numbers (eg numbers with no factor `>2^16`),
280
+ allocating the storage required for `factor(n)` can introduce significant overhead.
281
+ """
282
+ eachfactor (n:: Integer ) = FactorIterator (n)
283
+
284
+ # state[1] is the current number to factor (this decreases when factors are found)
285
+ # state[2] is the prime to start trial division with.
286
+ function iterate (f:: FactorIterator{T} , state= (f. n, T (3 ))) where T
287
+ n, p:: T = state
288
+ if n <= p
289
+ n == 1 && return nothing
290
+ if n < 0
291
+ # if n is typemin, we can't negate it properly
292
+ # instead we set p=n which we can detect here.
293
+ if isa (n, BitSigned) && n == typemin (T)
294
+ if n != p
295
+ return (T (- 1 ), 1 ), (n, n)
296
+ end
297
+ return (T (2 ), 8 * sizeof (T) - 1 ), T .((1 , 1 ))
298
+ end
299
+ return (T (- 1 ), 1 ), (- n, p)
270
300
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
301
+ n == 0 && return (T (n), 1 ), (T (1 ), p)
278
302
end
303
+ tz = trailing_zeros (n)
304
+ tz> 0 && return (T (2 ), tz), (n >> tz, p)
279
305
if n <= N_SMALL_FACTORS
306
+ p = _min_factor (n)
307
+ num_p = 1
280
308
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
309
+ n = div (n, p)
310
+ n == 1 && break
311
+ _min_factor (n) == p || break
312
+ num_p += 1
288
313
end
289
- elseif isprime (n)
290
- return increment! (h, 1 , n)
314
+ return (p, num_p), (n, p)
315
+ elseif p == 3 && isprime (n)
316
+ return (n, 1 ), (T (1 ), n)
291
317
end
292
- local p:: T
293
- for p in 3 : 2 : N_SMALL_FACTORS
294
- _min_factor (p) == 1 || continue
318
+ for p in p: 2 : N_SMALL_FACTORS
319
+ _min_factor (p) == p || continue
295
320
num_p = 0
296
321
while true
297
322
q, r = divrem (n, T (p)) # T(p) so julia <1.9 uses fast divrem for `BigInt`
298
323
r == 0 || break
299
324
num_p += 1
300
325
n = q
301
326
end
302
- # h[p] += num_p (about 2x faster, but the speed only matters for small numbers)
303
327
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)
328
+ return (p, num_p), (n, p+ 2 )
307
329
end
308
330
p* p > n && break
309
331
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)
332
+ # if n < 2^32, then if it wasn't prime, we would have found the factors by trial division
333
+ if n <= 2 ^ 32 || isprime (n)
334
+ return (n, 1 ), (T (1 ), n)
335
+ end
336
+ should_widen = T <: BigInt || widemul (n - 1 , n - 1 ) ≤ typemax (n)
337
+ p = should_widen ? pollardfactor (n) : pollardfactor (widen (n))
338
+ num_p = 0
339
+ while true
340
+ q, r = divrem (n, p)
341
+ r != 0 && return (p, num_p), (n, p)
342
+ num_p += 1
343
+ n = q
344
+ end
345
+ end
346
+
347
+ function factor! (n:: T , h:: AbstractDict{K,Int} ) where {T<: Integer ,K<: Integer }
348
+ for (p, num_p) in eachfactor (n)
349
+ increment! (h, num_p, p)
350
+ end
351
+ return h
313
352
end
314
353
315
354
@@ -425,15 +464,15 @@ julia> radical(2*2*3)
425
464
6
426
465
```
427
466
"""
428
- radical (n) = prod (factor (Set, n))
467
+ radical (n) = n == 1 ? one (n) : prod (p for (p, num_p) in eachfactor ( n))
429
468
430
- function pollardfactors! (n:: T , h :: AbstractDict{K,Int} ) where {T<: Integer ,K <: Integer }
469
+ function pollardfactor (n:: T ) where {T<: Integer }
431
470
while true
432
471
c:: T = rand (1 : (n - 1 ))
433
472
G:: T = 1
434
- r:: K = 1
473
+ r:: T = 1
435
474
y:: T = rand (0 : (n - 1 ))
436
- m:: K = 100
475
+ m:: T = 100
437
476
ys:: T = 0
438
477
q:: T = 1
439
478
x:: T = 0
@@ -446,7 +485,7 @@ function pollardfactors!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Inte
446
485
y = y^ 2 % n
447
486
y = (y + c) % n
448
487
end
449
- k:: K = 0
488
+ k:: T = 0
450
489
G = 1
451
490
while k < r && G == 1
452
491
ys = y
@@ -467,10 +506,13 @@ function pollardfactors!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Inte
467
506
G = gcd (x > ys ? x - ys : ys - x, n)
468
507
end
469
508
if G != n
470
- isprime (G) ? h[G] = get (h, G, 0 ) + 1 : pollardfactors! (G, h)
471
509
G2 = div (n,G)
472
- isprime (G2) ? h[G2] = get (h, G2, 0 ) + 1 : pollardfactors! (G2, h)
473
- return h
510
+ f = min (G, G2)
511
+ _gcd = gcd (G, G2)
512
+ if _gcd != 1
513
+ f = _gcd
514
+ end
515
+ return isprime (f) ? f : pollardfactor (f)
474
516
end
475
517
end
476
518
end
@@ -569,8 +611,16 @@ positive integers less than or equal to ``n`` that are relatively prime to
569
611
The totient function of `n` when `n` is negative is defined to be
570
612
`totient(abs(n))`.
571
613
"""
572
- function totient (n:: Integer )
573
- totient (factor (abs (n)))
614
+ function totient (n:: T ) where T<: Integer
615
+ n = abs (n)
616
+ if n == 0
617
+ throw (ArgumentError (" ϕ(0) is not defined" ))
618
+ end
619
+ result = one (T)
620
+ for (p, k) in eachfactor (n)
621
+ result *= p^ (k- 1 ) * (p - 1 )
622
+ end
623
+ result
574
624
end
575
625
576
626
# add: checked add (when makes sense), result of same type as first argument
0 commit comments