加快对Carmichael号码的搜索?

时间:2018-08-13 16:16:29

标签: python python-3.x primes

这里的主要问题是:在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')

2 个答案:

答案 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测试

我非常确定您对Carmichael号码的支票已经取消。如果numpy 表示所有整数 pow(b, n) % n == 1,而不是全部b表示Carmichael。您无法通过这种方式进行检查,因此需要其他规则。

如果所有b < n的{​​{1}}都为pow(b, n-1) % n == 1b = 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'