这里的主要问题是:在Python中使用“全部”还有更好的方法吗? 我已经读过它经历了所有条件,然后再回来查看是否为真。我想一次检查一种情况,然后在不起作用时立即退出。我相信这叫做“短路.....”。我不能使用一系列的“和”,因为它们会随输入而变化,并且可能有数百万个条件。
我正在寻找Carmichael numbers。卡迈克尔数的一个定义是,对于所有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')
答案 0 :(得分:1)
我能获得的最好成绩是通过重新安排您的条件(提速取决于输入的数字是否通过第一个条件)并使用math.gcd()
代替{{1}来达到4.5倍的提速。 }。
我也让他们返回一个字符串而不是打印一个。这应该更快,但是大多数情况下我是这样做的,因为它可以更轻松地测试计时。然后,您可以使用字符串执行任何操作:
fractions.gcd()
重新排列条件是可行的,因为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)
发生了短路(实际上and
也是如此),因此,如果第一个条件没有通过,Python将忽略第二个条件而继续前进。对于您的Carmichael测试,至少在我的测试中,检查单个all
的条件比检查gcd()
的条件要快。因此pow(b, n, n) == 1
测试应该首先进行。对于测试数字是否为质数的行,可能并不重要。在我的测试中,此更改使速度提高了约2倍。
我收到gcd()
的警告,所以我选择了fractions.gcd()
,它启动起来更快!那让我看到了其余的加速比。
当然,如果您需要一次检查数字的 ,则最好使用math.gcd()
并将其向量化。让我知道这是否是您的用例,我将看看是否可以为此考虑一个优化的版本。
我非常确定您对Carmichael号码的支票已经取消。如果numpy
表示所有整数 pow(b, n) % n == 1
,而不是全部b
表示Carmichael。您无法通过这种方式进行检查,因此需要其他规则。
如果所有b < n
的{{1}}都为pow(b, n-1) % n == 1
和b = 1, 2, ..., n
互质,则似乎可以使用一个数字是Carmichael的事实。 Here is a good example,以及上述示例中的代码(或多或少):
b
这比上面的选项要慢,但是我认为这在技术上是正确的:最好的一种正确方法。
答案 1 :(得分:1)
all
已经短路。无论任何来源使您认为不正确,要么是该来源有误,要么是您误解了。我们无法分辨。
不过,仍然可以轻松地加快速度。例如,您的gcd
呼叫正在测试num
是否与所有这些数字互质,但这是昂贵且不必要的。我们只需要检查可除性,就可以用更快的num % k != 0
来完成。此外,除数2可以排除比其他任何检查都多的数字,因此将其放在第一位将节省一些工作。另外,gcd(num,2)==1
中的elif
检查是多余的。
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'