From 8176b99e02c8d46c76ffa81bcfb7a197d5426e01 Mon Sep 17 00:00:00 2001
From: Rafael Fourquet <fourquet.rafael@gmail.com>
Date: Sun, 25 Jun 2017 13:45:17 +0200
Subject: [PATCH] make isprime(::BigInt) use deterministic algo when possible

---
 src/Primes.jl | 51 ++++++++++++++++++++++++++-------------------------
 1 file changed, 26 insertions(+), 25 deletions(-)

diff --git a/src/Primes.jl b/src/Primes.jl
index 53facd1..b380ca8 100644
--- a/src/Primes.jl
+++ b/src/Primes.jl
@@ -135,12 +135,23 @@ const PRIMES = primes(2^16)
 
 """
     isprime(n::Integer) -> Bool
+    isprime(n::Integer, reps) -> Bool
 
 Returns `true` if `n` is prime, and `false` otherwise.
 
+If `n ≤ 2^64` and `reps` is not specified, this is a deterministic test.
+Otherwise, the test is probabilistic, with a false positive rate less than
+`1/4^reps`.
+
+A value of `reps = 25` is considered safe for cryptographic applications
+(Knuth, Seminumerical Algorithms), and is the default when `n > 2^64`.
+
 ```julia
 julia> isprime(3)
 true
+
+juli> isprime(big(2)^130-1, 10)
+false
 ```
 """
 function isprime(n::Integer)
@@ -166,20 +177,8 @@ function isprime(n::Integer)
     return true
 end
 
-"""
-    isprime(x::BigInt, [reps = 25]) -> Bool
-
-Probabilistic primality test. Returns `true` if `x` is prime with high probability (pseudoprime);
-and `false` if `x` is composite (not prime). The false positive rate is about `0.25^reps`.
-`reps = 25` is considered safe for cryptographic applications (Knuth, Seminumerical Algorithms).
-
-```julia
-julia> isprime(big(3))
-true
-```
-"""
-isprime(x::BigInt, reps=25) = ccall((:__gmpz_probab_prime_p,:libgmp), Cint, (Ptr{BigInt}, Cint), &x, reps) > 0
-
+isprime(x::Integer, reps::Integer) =
+    ccall((:__gmpz_probab_prime_p,:libgmp), Cint, (Ptr{BigInt}, Cint), &(big(x)), reps) > 0
 
 # Miller-Rabin witness choices based on:
 #     http://mathoverflow.net/questions/101922/smallest-collection-of-bases-for-prime-testing-of-64-bit-numbers
@@ -217,19 +216,21 @@ function _witnesses(n::UInt64)
     i = xor((n >> 16), n) * 0x45d9f3b
     i = xor((i >> 16), i) * 0x45d9f3b
     i = xor((i >> 16), i) & 255 + 1
-    @inbounds return (Int(bases[i]),)
+    @inbounds return (bases[i] % Int,)
 end
 witnesses(n::Integer) =
-        n < 4294967296      ? _witnesses(UInt64(n)) :
-        n < 2152302898747   ? (2, 3, 5, 7, 11) :
-        n < 3474749660383   ? (2, 3, 5, 7, 11, 13) :
-                              (2, 325, 9375, 28178, 450775, 9780504, 1795265022)
-
-isprime(n::UInt128) =
-    n ≤ typemax(UInt64) ? isprime(UInt64(n)) : isprime(BigInt(n))
-isprime(n::Int128) = n < 2 ? false :
-    n ≤ typemax(Int64)  ? isprime(Int64(n))  : isprime(BigInt(n))
-
+        n <     4_294_967_296  ? _witnesses(n % UInt64) :
+        n < 2_152_302_898_747  ? (2, 3, 5, 7, 11) :
+        n < 3_474_749_660_383  ? (2, 3, 5, 7, 11, 13) :
+                                 (2, 325, 9375, 28178, 450775, 9780504, 1795265022)
+
+# the isprime implementation works faster with Unsigned types
+# than with their signed counterparts
+isprime(n::Base.BitSigned) = n < 2 ? false : isprime(unsigned(n))
+isprime(n::Union{UInt128,BigInt}) =
+    n < 2               ? false :
+    n ≤ typemax(UInt64) ? isprime(n % UInt64) :
+                          isprime(n, 25)
 
 # Trial division of small (< 2^16) precomputed primes +
 # Pollard rho's algorithm with Richard P. Brent optimizations