有效地找到接近10 ^ 9范围内的素数

时间:2016-12-01 17:59:26

标签: python algorithm math

范围是[10 ^ 9-10 ^ 6 tiill 10 ^ 9]。我已经尝试了所有我能找到并想到的东西 - 用Eratosthenes的Sieve预先计算并预先检查Fermat的Primality Test。但仍然无法在不到1分钟的时间内完成。

4 个答案:

答案 0 :(得分:3)

这需要不到一秒的时间:

Python 2.7.10 (default, Jun  1 2015, 18:05:38)
[GCC 4.9.2] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def primegen(start=0): # stackoverflow.com/a/20660551
...     if start <= 2: yield 2    # prime (!) the pump
...     if start <= 3: yield 3    # prime (!) the pump
...     ps = primegen()           # sieving primes
...     p = next(ps) and next(ps) # first sieving prime
...     q = p * p; D = {}         # initialization
...     def add(m, s):            # insert multiple/stride
...         while m in D: m += s  #   find unused multiple
...         D[m] = s              #   save multiple/stride
...     while q <= start:         # initialize multiples
...         x = (start // p) * p  #   first multiple of p
...         if x < start: x += p  #   must be >= start
...         if x % 2 == 0: x += p #   ... and must be odd
...         add(x, p+p)           #   insert in sieve
...         p = next(ps)          #   next sieving prime
...         q = p * p             #   ... and its square
...     c = max(start-2, 3)       # first prime candidate
...     if c % 2 == 0: c += 1     # must be odd
...     while True:               # generate infinite list
...         c += 2                #   next odd candidate
...         if c in D:            #   c is composite
...             s = D.pop(c)      #     fetch stride
...             add(c+s, s)       #     add next multiple
...         elif c < q: yield c   #   c is prime; yield it
...         else: # (c == q)      #   add p to sieve
...             add(c+p+p, p+p)   #     insert in sieve
...             p = next(ps)      #     next sieving prime
...             q = p * p         #     ... and its square
...
>>> ps = primegen(10**9-10**6)
>>> p = next(ps)
>>> result = []
>>> while p < 10**9:
...     result.append(p)
...     p = next(ps)
...
>>> print len(result)
47957

有关说明,请参阅 https://programmingpraxis.com/2015/07/31/incremental-sieve-of-eratosthenes/

答案 1 :(得分:2)

因为范围只有10 ^ 6。我认为Sieve不应该表现得那么糟糕 首先生成1到10 ^ 5之间的所有素数(因为10 ^ 5平方是10 ^ 10,最大数是10 ^ 9)。
然后使用筛子如下:
创建一个大小为10 ^ 6的数组,其中索引i表示,数字10 ^ 9-10 ^ 6 + i,然后使用您的主要列表划掉所有非素数。 在使用Sieve时,当然你应该删除所有偶数,最初然后在2到10 ^ 5范围内你只有近5000个素数。总的来说它大概是10 ^ 3 * 10 ^ 6,这是10 ^ 9步,这对现代处理器来说似乎并不复杂,运行时间。

答案 2 :(得分:1)

对于我来说,在macbook pro上大约需要28秒。你想要的素数在primes

import math 

def isPrime(n, primes):
   limit = int(math.sqrt(n))
   for i in primes:
      if i > limit:
         return True
      if n % i == 0:
         return False
   return True

low_primes = [2]
for i in range(3, 10**5, 2):
   if isPrime(i, low_primes):
      low_primes.append(i)

primes = []
for i in range(10**9-10**6 + 1, 10**9, 2):
   if isPrime(i, low_primes):
      primes.append(i)

答案 3 :(得分:0)

谢谢大家!我稍后会检查你的答案,现在想办法自己怎么做 - 在那里按相反的顺序应用方法 - 首先是Fermat,然后是Eratosphen。需要2-3秒。

n = 999000000
#n = 1  # should be 78499
m = n + 1000000


def eratosphene_filter(sorted_array_of_odd):
    biggest = sorted_array_of_odd[-1]
    smallest = sorted_array_of_odd[0]
    mapping ={i:True for i in sorted_array_of_odd}
    for i in range(3, int(biggest**0.5)+1, 2):
        j = nearest_from_bottom = (smallest // i) * i
        while j < biggest:
            if i!=j and j in mapping:
                mapping[j] = False
            j += i

    result = []
    for k,v in mapping.items():
        if v:
            result.append(k)
    return sorted(result)


def fermat_check(x, d=2):
    return pow(d, x-1, x) == 1


def primes_sieve(lower,top):
    if lower < 3:
        yield 1
        yield 2
        lower = 3

    all_numbers_in_range = range(lower if lower % 2 != 0 else lower + 1, top, 2)
    print(len(all_numbers_in_range))
    probably_primes = list(filter(fermat_check, all_numbers_in_range))
    print(len(probably_primes))
    print(probably_primes[:5],'...',probably_primes[-5:])

    primes_for_sure = list(eratosphene_filter(probably_primes))
    print(len(primes_for_sure))
    for i in  primes_for_sure:
        yield i


found_primes = list(primes_sieve(n, m))

print(found_primes[:5],'...',found_primes[-5:])

print(len(found_primes))