所有数字的乘法(2个数字之间)python

时间:2016-04-23 12:23:41

标签: python algorithm exponent

我正在解决一个问题(这是我之前问过的this问题的扩展,可以找到here)要求我计算两个数之间的数字乘法,然后计算取幂:

我的第一种方法很简单:

    n0=n+1
    n1=n0+1
    while n1<=(p-1):
        n0=n1%p*n0%p
        n1+=1
    print  p-pow(n0,(p-2),p) 


constraints:
1 < P <= 2*10^9 , a prime number 
1 <= N <= 2*10^9
Abs(N-P) <= 1000

这里我的代码计算n(&lt; = 1000)个连续数字的乘法
但是当约束变为

0 < N < 4×10^18
1 < P < 4×10^18, a prime number
Abs(N-P) < 10^4

我的解决方案对于这些约束很慢并且超出了时间限制。我搜索了各种改进代码的方法。我找到了一个很好的算法,它可以在O(loglog nM(nlogn))时间内计算阶乘,其中M是两个数相乘的时间复杂度。 该算法首先计算素数然后计算n中素数的指数!然后最后将它们全部相乘(你可以在here上看到更多)。但是如果我在我的问题中实现这个解决方案,我认为它不会有所帮助,因为约束太大而无法在相当长的时间内计算所有质数本身,而我只需找到连续数字的最多10**4倍。所以我放弃了这个想法并寻找乘法。

我发现python乘法足够快它使用'Karatsuba算法'并且实现Schönhage-Strassen算法是不明智的(因为我首先想到实现这个) 除非有至少10,000个数字(因为那时只有它执行karatsuba)。

并且内置的pow()也非常快(this file的第1426行显示了实现math.pow的Python代码,但基本上归结为调用标准C库,它可能具有该函数的高度优化版本)用于计算约束条件下的取幂。

现在我无法想到任何其他方法来改善代码的时间复杂性。有人可以帮助我找到优化或完全不同的更好的解决时间约束的解决方案。

我要解决的问题是here

2 个答案:

答案 0 :(得分:1)

将代码更改为:

可以实现一个简单的* 2加速
n0=n+1
for n1 in range(n0+1,p):
    n0 = (n0 * n1)%p
return p-pow(n0,(p-2),p) 

每次迭代只执行一次模数运算。

额外的10次加速可以来自预计算阶乘。 您将乘以从n + 1到p-1的所有值,这与乘以-1到n + 1-p相同。因此,您可以预先计算一个等于-1 * -2 ... * - x乘积的数组A [x],并使用此预先计算的值而不是循环。

(请注意,您需要将此预先计算的数组保持为完整的整数精度,因为在预计算期间您不知道将使用哪个素数。)

预计算代码为:

t=1
A=[1]
for y in range(1,10**4+1):
    A.append(t)
    t*=-y

然后针对每种情况进行计算:

return 0 if n>=p else p-pow(A[p-n]%p,(p-2),p) 

答案 1 :(得分:0)

[修改] Stirling's formula表示对于大N,您可以使用日志估算N!,而计算机的数字更容易处理:

N! % p =~ exp((N* ln(N) - N)) % p

对于较小的数字,请保持阶乘以获得更高的精度。