EITF55-project1/py/milrab.py
2025-02-16 09:11:06 +01:00

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