这来自math.se post。我正在检查2^(n-1)+3
是否可以被n整除。这是我写的代码,
def ck(n):
c=pow(2,n-1,n)+3
return not c%n
for i in range(10**7,2*10**7):
if ck(i):
print(i)
break
print('Search Complete')
函数ck
首先使用buit-in 2^(n-1)%n
计算pow
,添加3并最终得到余数。在数学上,这与(2^(n-1)+3)%n
相同,但速度要快得多,因为计算pow(a,b,c)
的速度比pow(a,b)%c
快
我想知道我是否可以进行其他优化(在函数或for循环中)?
range(10**7,2*10**7)
中的值只是虚拟值,我逐步增加,以便搜索不会失控。
[在某人得到错误的想法之前,我完全不破解哈希]
答案 0 :(得分:1)
这个版本稍微快一些,因为我们在这里放弃了函数调用开销:
print(next(i for i in range(lowerbound,upperbound) if not (pow(2,i-1,i)+3)%i), 'Search Complete')
这将通过我的快速和肮脏测量提供~10%的加速:
python /tmp/so1.py 46.54s user 0.00s system 99% cpu 46.558 total
VS
python /tmp/so2.py 52.50s user 0.01s system 99% cpu 52.530 total
我也试过,如果没有将%
的结果转换为bool,但使用0
测试对象标识会更快 - 但事实并非如此。
答案 1 :(得分:1)
我对@ ch3ka的答案进行了几次不同的修改,这是我找到的最快的版本。
我维护gmpy2所以我用它来进行数值计算。 gmpy2使用GMP多精度库,并且使用Python的本机整数类型通常更快。使用gmpy2.powmod(...)
要比pow(...)
快得多。
从原始问题的链接,需要gcd(i,30) == 1
。接下来我尝试使用gmpy2.gcd(...)
来消除不可能的i值。这大大减少了一半的运行时间。
然后我通过七次通过范围取消了对gmpy2.gcd(...)
的调用。这再次将运行时间缩短了一半。最后,我使用concurrent.futures
将测试分布在4个核心上。
以下是最终版本:
import sys
import time
from gmpy2 import powmod
from concurrent import futures
BLOCKSIZE = 10**8
def blocktest(block):
start = max(10, block * BLOCKSIZE)
end = (block + 1) * BLOCKSIZE
now = time.time()
result = []
result.extend(i for i in range(30*(start//30) + 1, end, 30) if powmod(2, i-1, i) == i-3)
result.extend(i for i in range(30*(start//30) + 7, end, 30) if powmod(2, i-1, i) == i-3)
result.extend(i for i in range(30*(start//30) + 11, end, 30) if powmod(2, i-1, i) == i-3)
result.extend(i for i in range(30*(start//30) + 13, end, 30) if powmod(2, i-1, i) == i-3)
result.extend(i for i in range(30*(start//30) + 17, end, 30) if powmod(2, i-1, i) == i-3)
result.extend(i for i in range(30*(start//30) + 19, end, 30) if powmod(2, i-1, i) == i-3)
result.extend(i for i in range(30*(start//30) + 23, end, 30) if powmod(2, i-1, i) == i-3)
result.extend(i for i in range(30*(start//30) + 29, end, 30) if powmod(2, i-1, i) == i-3)
return (start, end - 1, time.time() - now, result)
if __name__ == "__main__":
print("starting time: ", time.strftime("%H:%M:%S"))
with futures.ProcessPoolExecutor(max_workers=4) as executor:
for s, e, t, r in executor.map(blocktest, range(10)):
print("range({:,}, {:,}) time: {} et: {:6.2f} {!r}".format(s, e, time.strftime("%H:%M:%S"), t, r))
测试到10 ** 9大约需要1分15秒。只花了16分多钟才找到第一个成功的价值:13957196317。