x = 2**1000000
n = 2**100000000
(x**2-2)%n
太慢。我找到了pow(),但是我不能使用它,因为我不能减去2。(pow(x, 2)-2)%n
和(x*x-2)%n
也很慢。当我测试(x*x-2)
时很快,但是当我添加模运算符时却很慢。有没有一种方法可以更快地计算(x**2-2)%n
?
答案 0 :(得分:8)
您在解释器中运行此命令吗?我做了一些测试,发现主要的减速似乎来自解释器试图显示结果。
如果将表达式分配给变量,则解释器将不会尝试显示结果,并且很快:
x = 2**1000000
n = 2**100000000
result = (x**2-2)%n
附录:
我本来也想与MikeW的回答相同,如果您想让代码的每个部分更快,您可以利用Python内部的整数基数2表示法并使用按位左移:
x = 1 << 1000000
n = 1 << 100000000
要注意的是,这仅适用于x
和n
为2的幂的情况,因此您必须格外小心,以免出现一次错误。 This answer很好地说明了移位的基本原理,但是Python与其他语言(例如C,C ++或Java)有点不同,因为Python整数是unlimited precision,所以您永远都不能完全离开移位就像其他语言一样。
答案 1 :(得分:1)
如果x始终是2的幂,并且n始终是2的幂,那么您可以使用字节数组上的位运算来轻松快速地对其进行计算,然后可以将其重新构造为“数字”。
如果2 ^ N为(二进制)1后跟N个零,那么(2 ^ N)^ 2为(二进制)1后跟2N个零。
2^3 squared is b'1000000'
如果您有数字2 ^ K(二进制1,后跟K个零),那么2 ^ K-2将是K-1 1(一个),后跟零。
eg 2^4 is 16 = b'10000', 2^4 - 2 is b'1110'
如果您需要“%2 ^ M”,然后以二进制形式,则只需选择最后(低)个M位,而忽略其余位。
9999 is b'10011100001111'
9999 % 2^8 is b'00001111'
'
因此将各个部分组合起来,如果x = 2 ^ A和n = 2 ^ B,则
(x ^ 2-2)%n
将是:(二进制数的)(最后B位)(2 * A-1个“ 1”后跟一个“ 0”)
答案 2 :(得分:1)
一些模块规则:
1)(a + b)mod(n)= amod(n)+ bmod(N)
2)(a.b)mod(n)= amod(n).bmod(n)
因此您可以将方程式转换为:
(x ** 2-2)%n ==>(x.x-2)%n ==>(x%n)。(x%n)-(2%n)
如果n始终大于2,则(2%n)本身就是2。
求解(x%n):
如果x和n始终为2 **值;如果x> n,那么(x%n)= 0就是答案,如果x 所以答案是0-(2%n)或x ** 2-(2%n)
答案 3 :(得分:0)
如果要计算(x ** y-z)%n
相当于(((x ** y)%n-z)%n
Python pow函数包含一个模数作为可选参数,因为它非常常用,并且可以优化方式进行计算。所以你应该使用:
(pow(x, y, n) - z) % n
答案 4 :(得分:0)
OP在评论中说:这很慢,因为我将x分配给答案,然后重复该过程。
我尝试这个:
x = 2**(1000*1000)
n = 2**(100*1000*1000)
import time
t0=time.time()
for i in range(6):
x = (x*x-2)%n
t1=time.time()
print(i,t1-t0)
t0=t1
print(x<n)
"""
0 0.0
1 0.4962291717529297
2 0.5937404632568359
3 1.9043104648590088
4 5.708504915237427
5 16.74528479576111
True
"""
这表明在此问题中它变慢了,因为x
增长了,每个循环的位数翻了一番:
In [5]: %timeit u=x%n
149 ns ± 6.42 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
如果%n
,x<n
绝对不会花费时间。