我写了一个快速的筛子来测试一个数字是否为素数。我有两个问题:
1)我测试了一个200位数的素数,它错误地说它不是素数。我相信这是浮点错误(或类似的东西)。我怎样才能使这更准确?
2)有更好的方式来写这个吗?我用十进制来处理更大的数字。这是最好的方式吗?
import math
from decimal import *
def isprime(n):
i = 2
a = 1
if n == 1:
return 0
if n == 2 or n == 3:
return 1
while i < n**0.5 + 1:
if Decimal(math.fmod(n,i)) == 0:
a = 0
i = n
if Decimal(math.fmod(n,i)) != 0:
i += 1
a = 1
return a
答案 0 :(得分:2)
标准double浮点格式只能表示精确到2 ^ 53的整数(9007199254740992,16位);从那时起,可表示的整数之间存在差距,随着数字变大,这些差距会变大。
64位版本的python本身使用64位整数,在其他平台上你可以使用numpy的int64
。这不会让你接近200位数,但它会让你远离32位整数范围,以便天真的代码变得非常缓慢。
例如,当使用最多2 ^ 32或sqrt(2 ^ 32)/ 2 = 32767的整数时,试验分区只需要考虑最多pi(sqrt(2 ^ 32))= 6542个潜在的小素数除数奇数候选除数加上数字2,或者在使用阶数高于2的轮子时介于这两个极端之间。接近2 ^ 64,要测试的小素数的除数是pi(sqrt(2 ^ 64))= 203,280,221已经......
超过2 ^ 32的确定性素性测试是Miller-Rabin或Baillie-PSW等算法的范畴。米勒 - 拉宾在某些精确选定的基础上使用时,确定性达到某些阈值 - 大约在2 ^ 64之间。见The best known SPRP bases sets。 Baillie-PSW也被确定为至少2 ^ 64的确定性。
这意味着超过2 ^ 64你需要使用某种大整数类型,并且你必须使用概率算法进行素性测试(给你'工业级'素数而不是经过验证的素数)。或者计划花费大量的时间来实际证明200位数字的原始性...... 200位数字具有100位平方根(大约300位),所以即使计算所有潜在的小素数除数也是如此推动天真的试验分裂测试不再可行。