78 lines
1.7 KiB
Python
78 lines
1.7 KiB
Python
import random
|
|
import time
|
|
|
|
|
|
def lcg(seed, a=1664525, c=1013904223, m=2**32):
|
|
while True:
|
|
seed = (a * seed + c) % m
|
|
yield seed # Produces an infinite stream of numbers
|
|
|
|
|
|
rand_gen = lcg(42)
|
|
|
|
|
|
def randint(a, b) -> int:
|
|
return next(rand_gen) % (b - a + 1) + a
|
|
|
|
|
|
def milrab(n: int, iter: int = 5) -> bool:
|
|
"Miller-Rabin probabilistic primality test"
|
|
|
|
# These should need no further introduction
|
|
if n < 2:
|
|
return False
|
|
if n in (2, 3):
|
|
return True
|
|
if n % 2 == 0:
|
|
return False
|
|
|
|
# Keep in mind that here we know that m will be an even number
|
|
m = n - 1
|
|
k = 0
|
|
|
|
# Executed at least once
|
|
while m % 2 == 0:
|
|
m //= 2 # Int divide for int result type
|
|
k += 1
|
|
|
|
for _ in range(iter):
|
|
a = randint(2, n - 2) # Any integer in range 1 < a < n - 1
|
|
b = pow(a, m, n)
|
|
|
|
# Valid only for the first iteration
|
|
if b == 1 or b == n - 1:
|
|
continue # Likely a prime
|
|
|
|
# The rest, we start from 0
|
|
for _ in range(k - 1):
|
|
b = pow(b, 2, n)
|
|
if b == n - 1:
|
|
break # May be prime
|
|
if b == 1: # For sure not prime
|
|
return False
|
|
|
|
else: # Python way to branch if loop never calls break
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
assert milrab(53, 1) == True
|
|
assert milrab(53, 2) == True
|
|
assert milrab(53, 3) == True
|
|
assert milrab(53, 4) == True
|
|
assert milrab(203, 10) == False
|
|
|
|
assert milrab(10, 4) == False
|
|
|
|
start = time.perf_counter()
|
|
primes = []
|
|
for p in range(2**15, 2**16):
|
|
if milrab(p, 10):
|
|
primes.append(p)
|
|
end = time.perf_counter()
|
|
print(f"Time taken: {end - start:.6f} seconds")
|
|
|
|
|
|
for k in range(10):
|
|
assert milrab(53, k) == True
|