algorithm-in-python/math/numberTheory/isPrime.py

102 lines
2.2 KiB
Python
Raw Normal View History

2018-10-02 21:24:06 +08:00
''' mbinary
#########################################################################
# File : isPrime.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
2019-01-31 12:09:46 +08:00
# Blog: https://mbinary.xyz
2018-10-02 21:24:06 +08:00
# Github: https://github.com/mbinary
# Created Time: 2018-03-04 21:34
2018-10-02 21:24:06 +08:00
# Description:
#########################################################################
'''
from random import randint
2018-10-02 21:24:06 +08:00
2020-04-15 12:28:20 +08:00
def quickMulMod(a, b, m):
'''a*b%m, quick'''
ret = 0
while b:
2020-04-15 12:28:20 +08:00
if b & 1:
ret = (a+ret) % m
b //= 2
a = (a+a) % m
return ret
2020-04-15 12:28:20 +08:00
def quickPowMod(a, b, m):
'''a^b %m, quick, O(logn)'''
2020-04-15 12:28:20 +08:00
ret = 1
while b:
2020-04-15 12:28:20 +08:00
if b & 1:
ret = quickMulMod(ret, a, m)
b //= 2
a = quickMulMod(a, a, m)
return ret
2020-04-15 12:28:20 +08:00
def isPrime(n, t=5):
'''miller rabin primality test, a probability result
t is the number of iteration(witness)
'''
2020-04-15 12:28:20 +08:00
t = min(n-3, t)
if n < 2:
print('[Error]: {} can\'t be classed with prime or composite'.format(n))
return
2020-04-15 12:28:20 +08:00
if n == 2:
return True
d = n-1
r = 0
2020-04-15 12:28:20 +08:00
while d % 2 == 0:
r += 1
d //= 2
tested = set()
for i in range(t):
2020-04-15 12:28:20 +08:00
a = randint(2, n-2)
while a in tested:
2020-04-15 12:28:20 +08:00
a = randint(2, n-2)
tested.add(a)
2020-04-15 12:28:20 +08:00
x = quickPowMod(a, d, n)
if x == 1 or x == n-1:
continue # success,
for j in range(r-1):
2020-04-15 12:28:20 +08:00
x = quickMulMod(x, x, n)
if x == n-1:
break
else:
return False
return True
2020-04-15 12:28:20 +08:00
'''
we shouldn't use Fermat's little theory
Namyly:
For a prime p, and any number a where (a,n)=1
a ^(p-1) \equiv 1 (mod p)
The inverse theorem of it is not True.
a counter-example: 2^340 \equiv 1 (mod 341), but 341 is a composite
'''
2020-04-15 12:28:20 +08:00
def twoDivideFind(x, li):
a, b = 0, len(li)
while a <= b:
2018-10-02 21:24:06 +08:00
mid = (a+b)//2
2020-04-15 12:28:20 +08:00
if li[mid] < x:
a = mid+1
elif li[mid] > x:
b = mid-1
else:
return mid
return -1
2020-04-15 12:28:20 +08:00
if __name__ == '__main__':
n = 100
2020-04-15 12:28:20 +08:00
print('prime numbers below', n)
print([i for i in range(n) if isPrime(i)])
while 1:
n = int(input('n: '))
print(isPrime(n))