Skip to content

Commit 814a10a

Browse files
author
oscarddssmith
committed
use BPSW for primality testing
1 parent c01d2c9 commit 814a10a

File tree

1 file changed

+49
-61
lines changed

1 file changed

+49
-61
lines changed

src/Primes.jl

Lines changed: 49 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -164,30 +164,67 @@ 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 <2 && return false
168+
n typemax(Int64) && return isprime(Int64(n))
169+
return isprime(BigInt(n))
170+
end
171+
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
172176
if n < N_SMALL_FACTORS
177+
n < 2 && return false
173178
return _min_factor(n) == n
174179
end
180+
iseven(n) && return false
175181
for m in (3, 5, 7, 11, 13, 17, 19, 23)
176182
n % m == 0 && return false
177183
end
184+
# miller-raben
178185
s = trailing_zeros(n - 1)
179186
d = (n - 1) >>> s
180-
for a in witnesses(n)::Tuple{Vararg{Int}}
181-
x = powermod(a, d, n)
182-
x == 1 && continue
187+
x::T = powermod(2, d, n)
188+
if x != 1
183189
t = s
184190
while x != n - 1
185191
(t -= 1) 0 && return false
186-
x = oftype(n, widemul(x, x) % n)
192+
x = widemul(x, x) % n
187193
x == 1 && return false
188194
end
189195
end
190-
return true
196+
197+
isqrt(n)^2 == n && return false
198+
# find Lucas test params
199+
D::T = 5
200+
for (s, d) in zip(Iterators.cycle((1,-1)), 5:2:n)
201+
D = s*d
202+
kronecker(D, n) == -1 && break
203+
end
204+
# Lucas test with P=1
205+
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
225+
end
226+
end
227+
return U == 0
191228
end
192229

193230
"""
@@ -200,56 +237,7 @@ julia> isprime(big(3))
200237
true
201238
```
202239
"""
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)
212-
const bases = UInt16[
213-
15591, 2018, 166, 7429, 8064, 16045, 10503, 4399, 1949, 1295, 2776, 3620,
214-
560, 3128, 5212, 2657, 2300, 2021, 4652, 1471, 9336, 4018, 2398, 20462,
215-
10277, 8028, 2213, 6219, 620, 3763, 4852, 5012, 3185, 1333, 6227, 5298,
216-
1074, 2391, 5113, 7061, 803, 1269, 3875, 422, 751, 580, 4729, 10239,
217-
746, 2951, 556, 2206, 3778, 481, 1522, 3476, 481, 2487, 3266, 5633,
218-
488, 3373, 6441, 3344, 17, 15105, 1490, 4154, 2036, 1882, 1813, 467,
219-
3307, 14042, 6371, 658, 1005, 903, 737, 1887, 7447, 1888, 2848, 1784,
220-
7559, 3400, 951, 13969, 4304, 177, 41, 19875, 3110, 13221, 8726, 571,
221-
7043, 6943, 1199, 352, 6435, 165, 1169, 3315, 978, 233, 3003, 2562,
222-
2994, 10587, 10030, 2377, 1902, 5354, 4447, 1555, 263, 27027, 2283, 305,
223-
669, 1912, 601, 6186, 429, 1930, 14873, 1784, 1661, 524, 3577, 236,
224-
2360, 6146, 2850, 55637, 1753, 4178, 8466, 222, 2579, 2743, 2031, 2226,
225-
2276, 374, 2132, 813, 23788, 1610, 4422, 5159, 1725, 3597, 3366, 14336,
226-
579, 165, 1375, 10018, 12616, 9816, 1371, 536, 1867, 10864, 857, 2206,
227-
5788, 434, 8085, 17618, 727, 3639, 1595, 4944, 2129, 2029, 8195, 8344,
228-
6232, 9183, 8126, 1870, 3296, 7455, 8947, 25017, 541, 19115, 368, 566,
229-
5674, 411, 522, 1027, 8215, 2050, 6544, 10049, 614, 774, 2333, 3007,
230-
35201, 4706, 1152, 1785, 1028, 1540, 3743, 493, 4474, 2521, 26845, 8354,
231-
864, 18915, 5465, 2447, 42, 4511, 1660, 166, 1249, 6259, 2553, 304,
232-
272, 7286, 73, 6554, 899, 2816, 5197, 13330, 7054, 2818, 3199, 811,
233-
922, 350, 7514, 4452, 3449, 2663, 4708, 418, 1621, 1171, 3471, 88,
234-
11345, 412, 1559, 194
235-
]
236-
237-
function _witnesses(n::UInt64)
238-
i = xor((n >> 16), n) * 0x45d9f3b
239-
i = xor((i >> 16), i) * 0x45d9f3b
240-
i = xor((i >> 16), i) & 255 + 1
241-
@inbounds return (Int(bases[i]),)
242-
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)
248-
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))
240+
isprime(x::BigInt, reps=25) = x>1 && is_probably_prime(x; reps=reps)
253241

254242
struct FactorIterator{T<:Integer}
255243
n::T
@@ -963,7 +951,7 @@ end
963951
"""
964952
divisors(f::Factorization) -> Vector
965953
966-
Return a vector with the positive divisors of the number whose factorization is `f`.
954+
Return a vector with the positive divisors of the number whose factorization is `f`.
967955
Divisors are sorted lexicographically, rather than numerically.
968956
"""
969957
function divisors(f::Factorization{T}) where {T<:Integer}

0 commit comments

Comments
 (0)