我使用了Rosetta Code中的一些代码。我重命名了一些东西,但我没有真正改变任何东西。
import random
def is_probable_prime(n, num_trials = 5):
assert n >= 2
if n == 2:
return True
if n % 2 == 0:
return False
s = 0
d = n-1
while True:
quotient, remainder = divmod(d, 2)
if remainder == 1:
break
s += 1
d = quotient
assert(2**s * d == n-1)
def try_composite(a):
if pow(a, d, n) == 1:
return False
for i in range(s):
if pow(a, 2**i * d, n) == n-1:
return False
return True
for i in range(num_trials):
a = random.randrange(2, n)
if try_composite(a):
return False
return True
它非常匹配一些伪代码。但是,当我测试数字时
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901
它返回False
。 Miller-Rabin的其他(python和java)实现为可能的素数返回True
。经过一些测试后,try_composite
仅在True
轮之后返回2
!我真的想知道任何错误,我猜错了缩进或某些我不知道的功能。
答案 0 :(得分:2)
在try_composite
函数中,for
循环应为for i in range(1,s)
。不要测试i
为零的情况。
编辑:此外,您在try_composite
功能中缺少测试。这是我的伪代码版本:
def isPrime(n, k=5):
def isComposite(s, d):
x = pow(randrange(2,n-1), d, n)
if x == 1 or x == n-1: return False
for r in range(1, s):
x = pow(x, 2, n)
if x == 1: return True
if x == n-1: return False
return True
if n < 2: return False
for p in [2, 3, 5, 7, 11, 13, 17]:
if n % p == 0: return n == p
s, d = 0, n-1
while d % 2 == 0: s, d = s+1, d/2
for i in range(k):
if isComposite(s, d): return False
return True
Python不允许在break
或continue
语句中使用标签,这太糟糕了。这是函数中更漂亮版本的伪代码:
function isPrime(n, k=5)
if n < 2 then return False
for p in [2,3,5,7,11,13,17,19,23,29]
if n % p == 0 then return n == p
s, d = 0, n-1
while d % 2 == 0
s, d = s+1, d/2
for i from 0 to k
x = powerMod(randint(2, n-1), d, n)
if x == 1 or x == n-1 then next i
for r from 1 to s
x = (x * x) % n
if x == 1 then return False
if x == n-1 then next i
return False
return True
请注意控制流转到next i
的两个位置。没有好的方法可以在Python中编写它。一种选择使用额外的布尔变量,可以对其进行设置和测试,以确定何时绕过其余代码。我上面提到的另一个选择是编写一个本地函数来执行任务。这个&#34;循环一半&#34;成语很方便实用;它由Guido提出PEP 3136和rejected。