原始测试需要比蛮力方法更长的时间,我该如何改进?

时间:2017-10-13 16:26:52

标签: python optimization primes bignum modular-arithmetic

我正在尝试在一台机器上计算素数,大小约为2 ^ 30-2 ^ 100 对于任何感兴趣的人,我的算法都包含在下面 我已经为每个数字优化了这个Python代码O(sqrt(n/2))(我相信):它只接受奇数,我确保传递给它的数字在另一个方法中是奇数。

我使用 Fermat素性测试来尝试加快这个过程。但是,对于内置math.pow()方法,数字太大,所以我使用了Squaring的Exponentiation。
然而,对于更大的数字来说这需要很长时间 - 使用蛮力会更快。

我的执行是否错误?
时间来自平方算法,它的重复堆栈也占用了我的记忆,我应该研究一个更快的算法吗?

要计算数字35184372088967是否为素数,使用我的强力算法需要.00100111秒,但需要.40608秒才能运行素数测试。

强力素数检查:

def isPrime(n):
    for i in range(3,int(math.sqrt(n)),2):
        if(n%i==0):
            return False
    return True

Fermat算法的实现:

def couldBePrime(n):
        if(n>308):
            return power(2,n-1)%n==1
        else:
            return math.pow(2,n-1)%n==1

通过平方算法进行指数化(耗时部分):

def power(base,exp):
    if exp == 0:
        return 1
    elif exp == 1:
        return base
    elif (exp & 1) != 0:
        return base * power(base * base, exp // 2)
    else:
        return power(base * base, exp // 2)

1 个答案:

答案 0 :(得分:5)

错误math.pow计算浮点值。浮点计算是近似的,在这里会给你无意义的结果。您需要进行整数计算,例如在power函数中执行(低效)。 Python的内置**运算符和pow函数(不是math.pow,它是一个不同的函数)都对整数进行操作。

在Python中,与许多编程语言一样,名为math的库专门用于浮点计算,而不是其他类型的数学计算,例如对整数进行的计算。

低效率:要计算b ^ e mod n,执行算术模n的效率要高得多,而不是先计算b ^ e然后将结果除以n。计算b ^ e需要构建一个非常大的数字,这将是缓慢的,因为随着计算越来越高的b次数,数字变得非常快。 (计算b ^ e的最佳方法不容易确定,但所有方法都涉及计算b的中间幂,唯一的实际不确定性是以什么顺序。)当你想要结果模n时,做所有连续乘法模数n:计算b ^ 2 mod n,然后平方并减去模n以得到b ^ 4 mod n等。每次执行乘法时,在除此之外,先将除数的余数除以n。

在Python中,标准库函数pow(记住, not math.pow)将为您完成。它就像

一样简单
def couldBePrime(n):
    return pow(2, n-1, n) == 1

如果Python没有这个函数,那么你的power函数是一种合理的实现方法,如果你减少每个中间结果的模数n。

def power(base, exp, mod):
    if exp == 0:
        return 1
    elif exp == 1:
        return base % mod
    elif (exp & 1) != 0:
        return (base * power((base * base) % mod, exp // 2, mod)) % mod
    else:
        return power((base * base) % mod, exp // 2)

当然,调用内置函数要快得多,因为这是执行操作的一种不错但不是非常好的方法,并且因为Python更易于编写而不是速度,所以最好是尽可能将数字重载提升到内置函数中。

另外需要注意:计算2的幂,有比乘法更快的方法 - 做bit shifting。但这在这里没有用,因为你想要计算2 ^ e mod n而不是2 ^ e。