【问题标题】:Random prime Number in pythonpython中的随机素数
【发布时间】:2015-03-06 01:05:51
【问题描述】:

我目前已将 ↓ 设置为我的 randprime(p,q) 函数。有什么方法可以通过 genexplistcomp 之类的方法来压缩它?这是我的功能:

n = randint(p, q)
while not isPrime(n):
    n = randint(p, q)

【问题讨论】:

  • 似乎最好生成一个介于pq 之间的素数列表,然后从该列表中随机选择一个。
  • 您可以通过将最低位设置为 1 来增加一个数字成为素数的机会,从而使其成为奇数 - 只有一个偶素数,即 2。事实上,除素数之外的所有素数2 和 3 要么低于 1,要么高于 6 的倍数。
  • 我讨厌有人在不说明原因的情况下对问题投反对票,因为如果 OP 不知道问题出在哪里,他就无法解决它。
  • @HunterMcMillen,这取决于 p & q 的大小。对于较大的数字,这将更有效。此外,如果你正在做一个数字筛(生成素数的最简单方法),那么你需要从 1 开始。
  • 拜托各位,这个问题缺乏特异性,这里的很多来回都是由此产生的。你能责怪那个而不是其他回答者吗?

标签: python random generator list-comprehension primes


【解决方案1】:

最好只生成素数列表,然后从该行中选择。 照原样,您的代码极有可能陷入无限循环,如果区间中没有素数,或者如果randint 总是选择非素数,那么while 循环将永远不会结束。

所以这可能更短,更不麻烦:

import random
primes = [i for i in range(p,q) if isPrime(i)]
n = random.choice(primes)

这样做的另一个好处是,如果区间中没有素数,就不会出现死锁。如前所述,这可能会很慢,具体取决于范围,因此如果您提前缓存素数会更快:

# initialising primes
minPrime = 0
maxPrime = 1000
cached_primes = [i for i in range(minPrime,maxPrime) if isPrime(i)]

#elsewhere in the code
import random
n = random.choice([i for i in cached_primes if p<i<q])

同样,进一步的优化是可能的,但在很大程度上取决于您的实际代码......而且您知道他们所说的过早优化。

【讨论】:

  • 如果 p 和 q 的数量级为 10**10,这可能是一个非常糟糕的主意,如果您正在考虑加密,这是一个合理的尝试。
  • 我猜如果pq之间有任何素数,它肯定会死锁。
  • 嗯,大概他们会缓存isPrime 检查,或者有一个预建的列表可供使用。
  • @LegoStormtroopr - 不一定。当使用大素数时(例如,用于 RSA 加密),通常的方法是检查小数,然后使用统计方法 - 请参阅 en.wikipedia.org/wiki/Primality_test#Probabilistic_tests(因为对于 2048 位素数来说,完整的测试将花费数年时间) -在素数上的每次测试都会成功,在非素数上的每次测试都有 50% 的机会表明该数字是非素数。确定您想要的概率有多低,并运行适当数量的测试。
  • 人们只是对加密和疯狂的大数做出疯狂的假设。这可能是本科一年级的编程问题。
【解决方案2】:

这是一个用python编写的脚本,用于在两个给定整数之间生成n个随机素数:


import numpy as np

def getRandomPrimeInteger(bounds):

    for i in range(bounds.__len__()-1):
        if bounds[i + 1] > bounds[i]:
            x = bounds[i] + np.random.randint(bounds[i+1]-bounds[i])
            if isPrime(x):
                return x

        else:
            if isPrime(bounds[i]):
                return bounds[i]

        if isPrime(bounds[i + 1]):
            return bounds[i + 1]

    newBounds = [0 for i in range(2*bounds.__len__() - 1)]
    newBounds[0] = bounds[0]
    for i in range(1, bounds.__len__()):
        newBounds[2*i-1] = int((bounds[i-1] + bounds[i])/2)
        newBounds[2*i] = bounds[i]

    return getRandomPrimeInteger(newBounds)

def isPrime(x):
    count = 0
    for i in range(int(x/2)):
        if x % (i+1) == 0:
            count = count+1
    return count == 1



#ex: get 50 random prime integers between 100 and 10000:
bounds = [100, 10000]
for i in range(50):
    x = getRandomPrimeInteger(bounds)
    print(x)

【讨论】:

    【解决方案3】:

    因此,如果您可以使用迭代器以随机顺序(无需替换)给出从 p 到 q 的整数,那就太好了。我一直无法找到一种方法来做到这一点。以下将给出该范围内的随机整数,并将跳过已经测试过的任何内容。

    import random
    fail = False
    tested = set([])
    n = random.randint(p,q)
    while not isPrime(n):
        tested.add(n)
        if len(tested) == p-q+1:
            fail = True
            break
        while n in s:
            n = random.randint(p,q)
    
    if fail:
        print 'I failed'
    else:
        print n, ' is prime'
    

    这样做的最大好处是,如果说您正在测试的范围只是 (14,15),那么您的代码将永远运行。如果存在这样的素数,则此代码保证会产生答案,如果不存在这样的素数,则会告诉您不存在。您显然可以使这更紧凑,但我试图展示逻辑。

    【讨论】:

    • 是的,但是如果给定一个没有素数的范围,我的会完成,如果给定一个只有几个素数的范围,我的运行时间会大大减少。
    • OP 的代码是 3 行,但是如果 p 和 q 之间没有素数,它会死锁,所以它是不安全的。
    • 是我,我投了你一票,因为你的回答虽然介绍了一些有用的东西,但却与所问的完全相反 - Is there any way to condense this。我确实相信那部分不是我的。这不是我回答的基础,只是一个脚注。欢迎您将我的代码作为脚注(或其中的想法)合并到您的答案中。
    • @AMADANONInc。很好 - 你的代码是一行,但它仍然是原始代码的近 2 倍字符,需要导入 itertools,并且不能解决错误。是浓缩的吗?取出我的代码以消除错误,我的代码长度(以字符为单位)与您的基本相同。
    • @LegoStormtroopr 但如果整数范围非常大(这通常是人们试图生成随机素数时),它将无法在合理的时间内完成。这就是 RSA 加密有效的原因。
    【解决方案4】:
    next(i for i in itertools.imap(lambda x: random.randint(p,q)|1,itertools.count()) if isPrime(i))
    

    这从 itertools.count() 开始 - 这给出了一个无限集。

    每个数字都通过 itertools.imap() 映射到范围内的一个新随机数。 imap 类似于 map,但返回的是一个迭代器,而不是一个列表——我们不想生成一个无限随机数的列表!

    然后,找到并返回第一个匹配的数字。

    有效地工作,即使 p 和 q 相距甚远 - 例如1 和 10**30,生成完整列表是不行的!

    顺便说一下,这并不比你上面的代码更有效,而且一目了然更难理解 - 请考虑下一个程序员必须阅读你的代码,然后按照你的方式去做上面做了。那个程序员可能会在六个月后成为你,那时你已经忘记了这段代码应该做什么!

    P.S - 实际上,您可能希望将 count() 替换为 xrange (不是范围!),例如xrange((p-q)**1.5+20) 尝试不超过该次数(在小范围和大范围的有限测试之间取得平衡,如果成功,失败的可能性不超过 1/2%),否则,如另一篇文章中所建议的那样,你可能会永远循环。

    PPS - 改进:将 random.randint(p,q) 替换为 random.randint(p,q)|1 - 这使代码效率提高了一倍,但消除了结果为 2 的可能性。

    【讨论】:

    • 我考虑了q-p,然后简化为p,然后p**2。我的最新答案(刚刚决定)是 (q-p)**2。 q-p 可能还不够;如果您有两个数字,其中一个是素数(例如 q=18 和 p=19),那么您有 25% 的失败机会。随着范围的增加,覆盖范围内所有数字的机会减少(在range 中采样range 随机数)。
    • 在进行了一些搜索之后,一个非常糟糕的情况是选择 p=1425172824437699411 和 q=p+1475;在这个数字范围内,只有一个素数(和 1475 个非素数)。每个人都有 1475/1476 的机会成为非主要的,因此即使 1476 次尝试也有 37% 的机会失败。
    • 另一个计算表明(q-p)**2 尝试可能还不够 - 对于 q=p+1(其中 p 或 q 是素数),有 6% 的失败几率(=4)测试。我将修改我对(q-p)**2+20 的回答,它只会稍微慢一些,并且对小数字更有效。
    猜你喜欢
    • 2010-12-18
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 2017-12-11
    • 2014-06-12
    • 1970-01-01
    相关资源
    最近更新 更多