在python

时间:2016-07-17 00:30:50

标签: python python-3.x random primes

如何在Python中的范围内生成非素数随机数?

我很困惑如何创建一个能够在一定范围内产生非素数的算法。我是定义函数还是创建条件语句?我希望范围内的每个数字具有相同的概率。例如,在1 - 100中,每个非素数不会有1%的几率,而是有1.35%的几率。

2 个答案:

答案 0 :(得分:3)

现在,你对效率一无所知,这肯定会得到优化,但这应该可以解决问题。这应该是测试素数的有效算法:

import random

def isPrime(n):
    if n % 2 == 0 and n > 2: 
        return False

    return all(n % i for i in range(3, int(math.sqrt(n)) + 1, 2))

def randomNonPrime(rangeMin, rangeMax):
    nonPrimes = filter(lambda n: not isPrime(n), xrange(rangeMin, rangeMax+1))
    if not nonPrimes:
        return None

    return random.choice(nonPrimes)

minMax = (1000, 10000)
print randomNonPrime(*minMax)

在返回范围内所有非素数的列表后,从非素数列表中选择一个随机值,使得范围内任何非素数的选择与该范围内的任何其他非素数一样可能

修改

虽然你没有问过效率,但我感到很无聊,所以我想出了一种方法,这使得(1000, 10000000)范围内的import numpy import sympy def randomNonPrime(rangeMin, rangeMax): primesInRange = numpy.fromiter( sympy.sieve.primerange(rangeMin, rangeMax), dtype=numpy.uint32, count=-1 ) numbersInRange = numpy.arange(rangeMin, rangeMax+1, dtype=numpy.uint32) nonPrimes = numbersInRange[numpy.invert(numpy.in1d(numbersInRange, primesInRange))] if not nonPrimes.size: return None return numpy.random.choice(nonPrimes) minMax = (1000, 10000000) print randomNonPrime(*minMax) 在我的机器上花费的时间超过6秒而不是一分半钟:

k

这使用SymPy symbolic mathematics library来优化范围中素数的生成,然后使用NumPy过滤输出并选择随机非素数。

答案 1 :(得分:1)

选择的算法和想法非常依赖于您的确切用例,如@smarx所述。

假设:

  • 范围内的每个非素数都具有相同的选择概率/ 均匀度
  • 抽样数不是具有非常高的概率的素数就足够了(算法误报不如CPU-bugs& co。)
  • 采样范围可能很大(类似筛子的方法很慢)
  • 需要单个样品的高性能(无缓存;无需更换的样品)

方法

  • 范围内的随机数范例
  • 使用非常快速的概率素性测试检查此数字是否为素数
  • 观察第一个非素数时停止
  • 如果未找到号码,请在max_trials
  • 之后停止算法
  • max_trials - 通过Coupon-Collectors-Problem(wiki)的近似值设置值:每次观察每个候选人的预期样本数

方法的特征

  • 快速获取单个样本(单CPU上每秒10000个样本;给定范围,例如)
  • 易于证明一致性
  • 关于范围大小和范围位置(数字大小)的良好渐近行为

代码

    import random
    import math

    """ Miller-Rabin primality test
            source: https://jeremykun.com/2013/06/16/miller-rabin-primality-test/
    """

    def decompose(n):
       exponentOfTwo = 0

       while n % 2 == 0:
          n = n//2  # modified for python 3!
          exponentOfTwo += 1

       return exponentOfTwo, n

    def isWitness(possibleWitness, p, exponent, remainder):
       possibleWitness = pow(possibleWitness, remainder, p)

       if possibleWitness == 1 or possibleWitness == p - 1:
          return False

       for _ in range(exponent):
          possibleWitness = pow(possibleWitness, 2, p)

          if possibleWitness == p - 1:
             return False

       return True

    def probablyPrime(p, accuracy=100):
       if p == 2 or p == 3: return True
       if p < 2: return False

       exponent, remainder = decompose(p - 1)

       for _ in range(accuracy):
          possibleWitness = random.randint(2, p - 2)
          if isWitness(possibleWitness, p, exponent, remainder):
             return False

       return True

    """ Coupon-Collector Problem (approximation)
            How many random-samplings with replacement are expected to observe each element at least once
    """
    def couponcollector(n):
        return int(n*math.log(n))

    """ Non-prime random-sampling
    """
    def get_random_nonprime(min, max):
        max_trials = couponcollector(max-min)
        for i in range(max_trials):
            candidate = random.randint(min, max)
            if not probablyPrime(candidate):
                return candidate
        return -1

    # TEST
    print(get_random_nonprime(1000, 10000000))