Python 加快搜索卡迈克尔号码的速度?
这里的主要问题是:有没有更好的方法在Python中使用“all”? 我读过,它经历了每一个条件,然后回来看看是否有任何是真的。我想一次检查一个条件,然后一旦一个条件不起作用就退出。我相信这就是所谓的“短路……”。我不能使用一系列的“和”,因为它们会随着输入而改变,并且可能有数百万个条件 我在找。卡迈克尔数的一个定义是,对于所有1 我使用了代码:Python 加快搜索卡迈克尔号码的速度?,python,python-3.x,primes,Python,Python 3.x,Primes,这里的主要问题是:有没有更好的方法在Python中使用“all”? 我读过,它经历了每一个条件,然后回来看看是否有任何是真的。我想一次检查一个条件,然后一旦一个条件不起作用就退出。我相信这就是所谓的“短路……”。我不能使用一系列的“和”,因为它们会随着输入而改变,并且可能有数百万个条件 我在找。卡迈克尔数的一个定义是,对于所有1
def Carm(num):
if all(gcd(k,num) == 1 for k in range(3,int(round(num**0.5)),2)) and gcd(2,num) == 1:
print(num,'is a Prime Number')
elif all(pow(b,num,num)==b for b in range(1,num)) and gcd(num,2)==1:
print(num,'is a Carmichael Number')
else:
print(num,'is not a Carmichael Number')
对原问题的答复
我所能得到的最好结果是,通过重新排列您的条件(速度将取决于您输入的数字是否通过第一个条件)并使用math.gcd()
代替fracts.gcd()
,大约提高了4.5倍
我还让他们返回字符串,而不是打印字符串。这应该更快,但我之所以这么做,主要是因为它更容易测试计时。然后可以使用字符串执行任何操作:
def carm_math_reorder(num):
if math.gcd(2,num) == 1 and all(math.gcd(k,num) == 1 for k in
range(3, int(round(num**0.5)), 2)):
return 'Prime'
elif math.gcd(num, 2) == 1 and all(pow(b, num, num)==b for b in
range(1, num)):
return 'Carmichael'
return 'Composite' # implicit "else" return
% timeit [Carm(num) for num in range(1000)] # your implementation
16.9 ms ± 89.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
% timeit [carm_math_reorder(num) for num in range(1000)]
3.71 ms ± 45.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
重新排列条件是有效的,因为和
短路(实际上所有的
),所以如果第一个条件没有通过,Python将忽略第二个条件,然后继续。在您的Carmichael测试中,检查单个gcd()
的条件比检查pow(b,n,n)==1的条件快,至少在我的测试中是这样。因此,应该首先进行gcd()
测试。这可能与测试数字是否为素数的行无关。在我的测试中,这个变化导致了大约2倍的加速
我收到警告说fracts.gcd()
已被弃用,因此我改为使用math.gcd()
,这会更快地启动!这让我看到了其余的加速
当然,如果您需要一次检查许多数字,那么最好使用numpy
并将其矢量化。让我知道这是否是你的用例,我会看看我是否能想出一个很好的优化版本
校正卡迈克尔试验
我很确定你的卡迈克尔号码支票被取消了。如果对所有整数b
,而不是对所有b
,则一个数字是Carmichael。你不能这样检查,所以你需要一个不同的规则
如果pow(b,n-1)%n==1,b=1,2,…,n
的所有b
和n
都是同素数,那么看起来你可以使用一个数字是Carmichael的事实,以及上述示例中的代码(或多或少):
这比上面的选项慢,但我相信它在技术上是正确的:最好的一种是正确的。所有的
都已经短路了。无论什么来源使你认为它不是,要么是来源是错误的,要么是你误解了它。我们不知道
不过,加快速度仍然很容易。例如,您的gcd
调用正在测试num
是否与所有这些数字都是互质的,但这既昂贵又不必要。我们只需要检查整除性,这可以通过更快的num%k!=0
。此外,2的可除性排除了比任何其他检查更多的数字,因此将其放在第一位将节省一些工作。另外,在elif
中的gcd(num,2)==1
检查也是多余的
def is_carmichael(n):
# Requires a positive integer.
if n == 1:
return '1'
elif n % 2 != 0 and all(n % k != 0 for k in range(3, math.ceil(n**0.5), 2)):
return 'prime'
elif all(pow(k, n, n) == k for k in range(1, n)):
return 'carmichael'
else:
return 'non-carmichael composite'
首先,我会把你的条件颠倒过来和
短路:如果第一个条件为False
,则不检查第二个条件。如果你的一个条件比另一个条件慢很多,它应该排在最后。另外,你能发布你的gcd()
代码吗?非常感谢你的回复!我应该交换哪些条件?你能推荐最好的订单吗?gcd是从“分数”中导入的:从分数导入gcd
为什么您要通过所有的gcd计算来检查整除性?这非常有效,谢谢!!!另一种定义是,pow(b,n-1,n)=1表示所有bI认为您的第一次检查不正确。对于所有整数b
,而不是所有整数b
,至少,pow(b,n,n)=1
!这是不可能签入代码的。我想你必须检查使用情况,但我甚至不知道p-1 | n-1
是什么意思……我只是用我认为更正确的东西更新了答案。我敢肯定原来的支票有瑕疵。
def is_carmichael(n):
# Requires a positive integer.
if n == 1:
return '1'
elif n % 2 != 0 and all(n % k != 0 for k in range(3, math.ceil(n**0.5), 2)):
return 'prime'
elif all(pow(k, n, n) == k for k in range(1, n)):
return 'carmichael'
else:
return 'non-carmichael composite'