Skip to content

Commit aea3ccb

Browse files
committed
fixes
1 parent 814a10a commit aea3ccb

File tree

3 files changed

+90
-33
lines changed

3 files changed

+90
-33
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
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"
17+
IntegerMathUtils = "0.1.1"
1818
julia = "1"

src/Primes.jl

Lines changed: 88 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -164,27 +164,72 @@ true
164164
```
165165
"""
166166
function isprime(n::Integer)
167-
n <2 && return false
168167
n typemax(Int64) && return isprime(Int64(n))
169168
return isprime(BigInt(n))
170169
end
171170

172-
function isprime(n::T) where {T<:Signed}
173-
# Small precomputed primes + Baillie–PSW for primality testing:
174-
# https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test
175-
# https://mathworld.wolfram.com/LucasSequence.html
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)
176182
if n < N_SMALL_FACTORS
177183
n < 2 && return false
178184
return _min_factor(n) == n
179185
end
180-
iseven(n) && return false
186+
iseven(n) && return n == 2
181187
for m in (3, 5, 7, 11, 13, 17, 19, 23)
182188
n % m == 0 && return false
183189
end
184-
# miller-raben
190+
if n<2^32
191+
return miller_rabbin_test(_witnesses(UInt64(n)), n)
192+
end
193+
miller_rabbin_test(2, n) || return false
194+
return lucas_test(widen(n))
195+
end
196+
197+
const bases = UInt16[
198+
15591, 2018, 166, 7429, 8064, 16045, 10503, 4399, 1949, 1295, 2776, 3620,
199+
560, 3128, 5212, 2657, 2300, 2021, 4652, 1471, 9336, 4018, 2398, 20462,
200+
10277, 8028, 2213, 6219, 620, 3763, 4852, 5012, 3185, 1333, 6227, 5298,
201+
1074, 2391, 5113, 7061, 803, 1269, 3875, 422, 751, 580, 4729, 10239,
202+
746, 2951, 556, 2206, 3778, 481, 1522, 3476, 481, 2487, 3266, 5633,
203+
488, 3373, 6441, 3344, 17, 15105, 1490, 4154, 2036, 1882, 1813, 467,
204+
3307, 14042, 6371, 658, 1005, 903, 737, 1887, 7447, 1888, 2848, 1784,
205+
7559, 3400, 951, 13969, 4304, 177, 41, 19875, 3110, 13221, 8726, 571,
206+
7043, 6943, 1199, 352, 6435, 165, 1169, 3315, 978, 233, 3003, 2562,
207+
2994, 10587, 10030, 2377, 1902, 5354, 4447, 1555, 263, 27027, 2283, 305,
208+
669, 1912, 601, 6186, 429, 1930, 14873, 1784, 1661, 524, 3577, 236,
209+
2360, 6146, 2850, 55637, 1753, 4178, 8466, 222, 2579, 2743, 2031, 2226,
210+
2276, 374, 2132, 813, 23788, 1610, 4422, 5159, 1725, 3597, 3366, 14336,
211+
579, 165, 1375, 10018, 12616, 9816, 1371, 536, 1867, 10864, 857, 2206,
212+
5788, 434, 8085, 17618, 727, 3639, 1595, 4944, 2129, 2029, 8195, 8344,
213+
6232, 9183, 8126, 1870, 3296, 7455, 8947, 25017, 541, 19115, 368, 566,
214+
5674, 411, 522, 1027, 8215, 2050, 6544, 10049, 614, 774, 2333, 3007,
215+
35201, 4706, 1152, 1785, 1028, 1540, 3743, 493, 4474, 2521, 26845, 8354,
216+
864, 18915, 5465, 2447, 42, 4511, 1660, 166, 1249, 6259, 2553, 304,
217+
272, 7286, 73, 6554, 899, 2816, 5197, 13330, 7054, 2818, 3199, 811,
218+
922, 350, 7514, 4452, 3449, 2663, 4708, 418, 1621, 1171, 3471, 88,
219+
11345, 412, 1559, 194
220+
]
221+
222+
function _witnesses(n::UInt64)
223+
i = xor((n >> 16), n) * 0x45d9f3b
224+
i = xor((i >> 16), i) * 0x45d9f3b
225+
i = xor((i >> 16), i) & 255 + 1
226+
@inbounds return Int(bases[i])
227+
end
228+
229+
function miller_rabbin_test(a, n::T) where T<:Signed
185230
s = trailing_zeros(n - 1)
186231
d = (n - 1) >>> s
187-
x::T = powermod(2, d, n)
232+
x::T = powermod(a, d, n)
188233
if x != 1
189234
t = s
190235
while x != n - 1
@@ -193,40 +238,52 @@ function isprime(n::T) where {T<:Signed}
193238
x == 1 && return false
194239
end
195240
end
241+
return true
242+
end
196243

197-
isqrt(n)^2 == n && return false
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
198248
# find Lucas test params
199249
D::T = 5
200250
for (s, d) in zip(Iterators.cycle((1,-1)), 5:2:n)
201251
D = s*d
202-
kronecker(D, n) == -1 && break
252+
k = kronecker(D, n)
253+
k != 1 && break
203254
end
255+
k == 0 && return false
204256
# Lucas test with P=1
205257
Q::T = (1-D) >> 2
206-
U::T, V::T, Qk::T = 1, 1, Q #assert types for conversion
207-
k::T = (n + 1)# >> trailing_zeros(n + 1)
208-
b = Base.top_set_bit(k)
209-
while b > 0
210-
U = widemul(U, V) % n
211-
V = (widemul(V, V) - Qk - Qk) % n
212-
Qk = widemul(Qk, Qk) % n
213-
b -= 1
214-
if isodd(k >> (b - 1))
215-
Qk = widemul(Qk, Q) % n
216-
Utmp, Vtmp = widen(U) + V, V + widemul(U, D)
217-
if isodd(Utmp)
218-
Utmp += n
219-
end
220-
if isodd(Vtmp)
221-
Vtmp += n
222-
end
223-
U = (Utmp >> 1) % n
224-
V = (Vtmp >> 1) % n
258+
U::T, V::T, Qk::T = 1, 1, Q
259+
k::T = (n + 1)
260+
trail = trailing_zeros(k)
261+
k >>= trail
262+
for b in digits(k, base=2)[end-1:-1:1]
263+
U = mod(U*V, n)
264+
V = mod(V * V - Qk - Qk, n)
265+
Qk = mod(Qk*Qk, n)
266+
if b == 1
267+
Qk = mod(Qk*Q, n)
268+
U, V = U + V, V + U*D
269+
# adding n makes them even
270+
# so we can divide by 2 without causing problems
271+
isodd(U) && (U += n)
272+
isodd(V) && (V += n)
273+
U = mod(U >> 1, n)
274+
V = mod(V >> 1, n)
225275
end
226276
end
227-
return U == 0
277+
if U in 0
278+
return true
279+
end
280+
for _ in 1:trail
281+
V == 0 && return true
282+
V = mod(V*V - Qk - Qk, n)
283+
Qk = mod(Qk * Qk, n)
284+
end
285+
return false
228286
end
229-
230287
"""
231288
isprime(x::BigInt, [reps = 25]) -> Bool
232289
Probabilistic primality test. Returns `true` if `x` is prime with high probability (pseudoprime);

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)