【问题标题】:Primality test in python [duplicate]python中的素性测试[重复]
【发布时间】:2011-12-22 14:10:57
【问题描述】:

我正在尝试用 Python 做一个简单的素数测试。

根据维基百科,primality test 如下:

给定一个输入数 n,检查从 2 到 n - 1 的任何整数 m 是否能整除 n。如果 n 能被任何 m 整除,则 n 是合数,否则是素数。

我开始排除偶数 - 除了 2 - 作为素数的候选者

def prime_candidates(x):
    odd = range(1, x, 2)
    odd.insert(0, 2)
    odd.remove(1)
    return odd

然后根据上面的规则编写一个检查素数的函数。

def isprime(x):
    for i in range(2, x-1):
            if x % i == 0:
                    return False
            else:
                    return True

这是主函数,它遍历 8000 个素数候选者的列表并测试它们的素数

def main():
    end = 8000
    candidates = prime_candidates(end)
    for i in candidates:
            if isprime(i) and i < end:
                    print 'prime found ' + str(i)

问题在于 isprime 函数对非素数返回 True。

【问题讨论】:

  • candidates 可能只是 [2] + range(3, end, 2)。我不知道你为什么包括零。而且你不需要测试and i &lt; end;这是由range(..., end, ...) 保证的。
  • 请注意,您不必检查到n-1。检查到 sqrt(n) 就足够了,因为任何高于此的值肯定不会将其除或已经被一个小于平方根的数字检查。
  • 还要注意,所有提到的候选生成方法都会产生不必要的复制。 xs = range(1, x, 2); xs[0] = 2 不进行复制,使用 xrange(3.x 中的纯 range)和 itertools.chain 甚至可以避免一次存储多个候选者。
  • @PaulManta range 不接受 sqrt(n) 返回的浮点数,并且由于舍入错误,转换为 int 会弄乱结果。

标签: python primes


【解决方案1】:

如果概率算法足够,请查看Miller–Rabin primality test。你也可以证明一个数是素数,例如Elliptic Curve Primality Proving (ECPP),但这需要更多的努力。

一个简单的试除算法如下

def prime(a):
     return not (a < 2 or any(a % x == 0 for x in range(2, int(a ** 0.5) + 1)))

编辑: 这是一个更具教育意义的版本,因为第一个解决方案非常简洁,可能更难阅读:

from math import sqrt
def prime(a):
    if a < 2: return False
    for x in range(2, int(sqrt(a)) + 1):
        if a % x == 0:
            return False
    return True

我用sqrt(a) 代替了a ** 0.5 以使事情更清楚。平方根用于不考虑比我们需要的更多的因素。

【讨论】:

  • 问题说我必须使用试用除法。
  • 这是作业。练习是教授编程的一种手段!
  • @David:我不明白你的意思。显然,马哈茂德付出了努力……他提供了他的全部代码。向这个社区询问就像向 TA 寻求帮助一样,对吧?我完全同意我们不应该简单地提供答案,而是在调试作业方面提供帮助似乎非常具有社区意识。
  • @David:啊,明白了,我的错。无论如何,虽然引用可能有点多,但我仍然喜欢 Morten 的算法。它简明扼要,一开始很难学,但要发展却是一项伟大的技能。他还返回评估而不是单独的 T/F 语句,这也很容易引起注意。他暗示“审判部门”并没有那么有效。
  • @MikeWilliamson 这里的简洁性非常糟糕。更好的是多使用几行并添加一些解释变量。过于简洁是许多程序员的可怕失败。如果将它正确地分布在 4 或 5 行上,阅读起来会快得多。更容易阅读。更容易检查。对于初学者,比如提问的人,这个答案中的代码是黑魔法。
【解决方案2】:

简而言之,您的isprime(x) 检查数字是否为奇数,在if x % 2 == 0 之后立即退出。

尝试一个小的改变,以便您真正进行迭代:

def isprime(x):
    for i in range(2, x-1):
        if x % i == 0:
            return False
    else:
        return True

请注意,else: 现在是 for 循环的一部分,而不是 if 语句的一部分。

【讨论】:

  • 虽然这个解决方案完全没问题,但下面的解决方案在 d * d
  • 鉴于这是一项家庭作业,我不认为性能很重要。问题本身就是“出了什么问题”,毫无疑问如何让它变得更好。
  • 道歉...并不是要批评您的解决方案。你是对的。我只是想知道为什么社区投票这个解决方案而不是只上升到 sqrt(n) 的解决方案。
  • 有什么理由将第二次返回放在else 块中? for/else 构造相当少见,考虑到循环不包含 break 语句,这里不需要。
  • 那是两年前的事了。我想原因是为了尽量减少变化。
【解决方案3】:

您的函数实际上返回您的数字是否为奇数。

确实,您正在做的是检查 2 是否除以您的数字,然后立即返回。您永远不会检查其他数字。

你需要做的是把这个 return true 从 if 的 else 子句中取出,并将 for 循环返回到 main 函数体中。

在旁注中,如果您正在寻找低于给定数字的素数,您可以将找到的素数存储在内存中,然后只尝试将新数字除以这些素数! (因为如果 d 是合数并且整除 q,那么 p 存在使得 p 是素数并且 p整除 q)。

【讨论】:

    【解决方案4】:

    问题是您将return False 放在else 子句中,而不是放在函数的末尾。因此,您的函数将在检查第一个除数后立即返回,而不是继续检查其他除数。

    这是一个与您类似的简单素性测试:

    def is_prime(n):
        d = 2
        while d * d <= n:
            if n % d == 0:
                return False
            d += 1
        return n > 1
    

    【讨论】:

    • (我没有投反对票,但是......)计算一次平方根肯定比平方 n 次要便宜。此外,while 循环不是很 Pythonic。使用范围()。
    • 我同意 range 更 Pythonic,但 OTOH 整数乘法很便宜,而且 sqrt 方法需要四舍五入,这对我来说似乎不优雅。
    • 平方根上方的下一个整数不整除 n。因此向下取整是安全的,这就像转换为 int 一样简单。此外,我会在一周中的任何一天都偏爱 O(sqrt(N)) 而不是 O(N),优雅被诅咒(当然,在合理范围内)。
    • 你是对的,转换为 int 工作正常。但是这段代码也是 O(sqrt(n)),并且可能至少一样快,因为它没有列表查找(对于 python 2)或迭代器(对于 3)的开销。
    • 杜哈。今晚我的大脑半开半闭。
    猜你喜欢
    • 1970-01-01
    • 2014-03-26
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 2010-10-01
    • 2020-07-06
    相关资源
    最近更新 更多