Skip to content

Commit 42b4d92

Browse files
authored
Merge branch 'master' into master
2 parents dbd2765 + 8c20fb3 commit 42b4d92

File tree

4 files changed

+97
-53
lines changed

4 files changed

+97
-53
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1414
test = ["DataStructures", "IntegerMathUtils", "Test"]
1515

1616
[compat]
17-
IntegerMathUtils = "0.1"
18-
julia = "1"
17+
IntegerMathUtils = "0.1.1"
18+
julia = "1.6"

appveyor.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
environment:
22
matrix:
3-
- julia_version: 1.0
4-
- julia_version: 1.3
53
- julia_version: 1.6
6-
- julia_version: 1.7
4+
- julia_version: 1
75
- julia_version: nightly
86
matrix:
97
allow_failures:

src/Primes.jl

Lines changed: 93 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -164,51 +164,36 @@ true
164164
```
165165
"""
166166
function isprime(n::Integer)
167-
# Small precomputed primes + Miller-Rabin for primality testing:
168-
# https://en.wikipedia.org/wiki/Miller–Rabin_primality_test
169-
# https://github.com/JuliaLang/julia/issues/11594
170-
n < 2 && return false
171-
trailing_zeros(n) > 0 && return n==2
167+
n typemax(Int64) && return isprime(Int64(n))
168+
return isprime(BigInt(n))
169+
end
170+
171+
# Uses a polyalgorithm depending on the size of n.
172+
# n < 2^16: lookup table (we already have this table because it helps factor also)
173+
# n < 2^32: trial division + Miller-Rabbin test with base chosen by
174+
# Forišek and Jančina, "Fast Primality Testing for Integers That Fit into a Machine Word", 2015
175+
# (in particular, see function FJ32_256, from which the hash and bases were taken)
176+
# n < 2^64: Baillie–PSW for primality testing.
177+
# Specifically, this consists of a Miller-Rabbin test and a Lucas test
178+
# For more background on fast primality testing, see:
179+
# http://ntheory.org/pseudoprimes.html
180+
# http://ntheory.org/pseudoprimes.html
181+
function isprime(n::Int64)
182+
iseven(n) && return n == 2
172183
if n < N_SMALL_FACTORS
184+
n < 2 && return false
173185
return _min_factor(n) == n
174186
end
175187
for m in (3, 5, 7, 11, 13, 17, 19, 23)
176188
n % m == 0 && return false
177189
end
178-
s = trailing_zeros(n - 1)
179-
d = (n - 1) >>> s
180-
for a in witnesses(n)::Tuple{Vararg{Int}}
181-
x = powermod(a, d, n)
182-
x == 1 && continue
183-
t = s
184-
while x != n - 1
185-
(t -= 1) 0 && return false
186-
x = oftype(n, widemul(x, x) % n)
187-
x == 1 && return false
188-
end
190+
if n<2^32
191+
return miller_rabbin_test(_witnesses(UInt64(n)), n)
189192
end
190-
return true
193+
miller_rabbin_test(2, n) || return false
194+
return lucas_test(widen(n))
191195
end
192196

193-
"""
194-
isprime(x::BigInt, [reps = 25]) -> Bool
195-
Probabilistic primality test. Returns `true` if `x` is prime with high probability (pseudoprime);
196-
and `false` if `x` is composite (not prime). The false positive rate is about `0.25^reps`.
197-
`reps = 25` is considered safe for cryptographic applications (Knuth, Seminumerical Algorithms).
198-
```julia
199-
julia> isprime(big(3))
200-
true
201-
```
202-
"""
203-
isprime(x::BigInt, reps=25) = is_probably_prime(x; reps=reps)
204-
205-
# Miller-Rabin witness choices based on:
206-
# http://mathoverflow.net/questions/101922/smallest-collection-of-bases-for-prime-testing-of-64-bit-numbers
207-
# http://primes.utm.edu/prove/merged.html
208-
# http://miller-rabin.appspot.com
209-
# https://github.com/JuliaLang/julia/issues/11594
210-
# Forišek and Jančina, "Fast Primality Testing for Integers That Fit into a Machine Word", 2015
211-
# (in particular, see function FJ32_256, from which the hash and bases were taken)
212197
const bases = UInt16[
213198
15591, 2018, 166, 7429, 8064, 16045, 10503, 4399, 1949, 1295, 2776, 3620,
214199
560, 3128, 5212, 2657, 2300, 2021, 4652, 1471, 9336, 4018, 2398, 20462,
@@ -238,18 +223,79 @@ function _witnesses(n::UInt64)
238223
i = xor((n >> 16), n) * 0x45d9f3b
239224
i = xor((i >> 16), i) * 0x45d9f3b
240225
i = xor((i >> 16), i) & 255 + 1
241-
@inbounds return (Int(bases[i]),)
226+
@inbounds return Int(bases[i])
227+
end
228+
229+
function miller_rabbin_test(a, n::T) where T<:Signed
230+
s = trailing_zeros(n - 1)
231+
d = (n - 1) >>> s
232+
x::T = powermod(a, d, n)
233+
if x != 1
234+
t = s
235+
while x != n - 1
236+
(t -= 1) 0 && return false
237+
x = widemul(x, x) % n
238+
x == 1 && return false
239+
end
240+
end
241+
return true
242242
end
243-
witnesses(n::Integer) =
244-
n < 4294967296 ? _witnesses(UInt64(n)) :
245-
n < 2152302898747 ? (2, 3, 5, 7, 11) :
246-
n < 3474749660383 ? (2, 3, 5, 7, 11, 13) :
247-
(2, 325, 9375, 28178, 450775, 9780504, 1795265022)
248243

249-
isprime(n::UInt128) =
250-
n typemax(UInt64) ? isprime(UInt64(n)) : isprime(BigInt(n))
251-
isprime(n::Int128) = n < 2 ? false :
252-
n typemax(UInt64) ? isprime(UInt64(n)) : isprime(BigInt(n))
244+
function lucas_test(n::T) where T<:Signed
245+
s = isqrt(n)
246+
@assert s <= typemax(T) #to prevent overflow
247+
s^2 == n && return false
248+
# find Lucas test params
249+
D::T = 5
250+
for (s, d) in zip(Iterators.cycle((1,-1)), 5:2:n)
251+
D = s*d
252+
k = kronecker(D, n)
253+
k != 1 && break
254+
end
255+
k == 0 && return false
256+
# Lucas test with P=1
257+
Q::T = (1-D) >> 2
258+
U::T, V::T, Qk::T = 1, 1, Q
259+
k::T = (n + 1)
260+
trail = trailing_zeros(k)
261+
k >>= trail
262+
# get digits 1 at a time since digits allocates
263+
for b in ndigits(k,base=2)-2:-1:0
264+
U = mod(U*V, n)
265+
V = mod(V * V - Qk - Qk, n)
266+
Qk = mod(Qk*Qk, n)
267+
if isodd(k>>b) == 1
268+
Qk = mod(Qk*Q, n)
269+
U, V = U + V, V + U*D
270+
# adding n makes them even
271+
# so we can divide by 2 without causing problems
272+
isodd(U) && (U += n)
273+
isodd(V) && (V += n)
274+
U = mod(U >> 1, n)
275+
V = mod(V >> 1, n)
276+
end
277+
end
278+
if U in 0
279+
return true
280+
end
281+
for _ in 1:trail
282+
V == 0 && return true
283+
V = mod(V*V - Qk - Qk, n)
284+
Qk = mod(Qk * Qk, n)
285+
end
286+
return false
287+
end
288+
"""
289+
isprime(x::BigInt, [reps = 25]) -> Bool
290+
Probabilistic primality test. Returns `true` if `x` is prime with high probability (pseudoprime);
291+
and `false` if `x` is composite (not prime). The false positive rate is about `0.25^reps`.
292+
`reps = 25` is considered safe for cryptographic applications (Knuth, Seminumerical Algorithms).
293+
```julia
294+
julia> isprime(big(3))
295+
true
296+
```
297+
"""
298+
isprime(x::BigInt, reps=25) = x>1 && is_probably_prime(x; reps=reps)
253299

254300
struct FactorIterator{T<:Integer}
255301
n::T
@@ -963,7 +1009,7 @@ end
9631009
"""
9641010
divisors(f::Factorization) -> Vector
9651011
966-
Return a vector with the positive divisors of the number whose factorization is `f`.
1012+
Return a vector with the positive divisors of the number whose factorization is `f`.
9671013
Divisors are sorted lexicographically, rather than numerically.
9681014
"""
9691015
function divisors(f::Factorization{T}) where T

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ for T in [Int, BigInt], n = [1:1000;1000000]
116116
f = factor(n)
117117
@test n == prod(T[p^k for (p, k) = f])
118118
prime = n != 1 && length(f) == 1 && get(f, n, 0) == 1
119-
@test isprime(n) == prime
119+
@test isprime(n) == prime || n
120120

121121
s = primesmask(n)
122122
for k = 1:n

0 commit comments

Comments
 (0)