素数筛选算法

# -*- coding:utf-8 -*-
"""
@Author:    [email protected]
@Date:      2017-10-24

1、输出所有小于等于max的质数,这里提供两种方法:
    produce_prime1使用质数判断方法,一直遍历到某一个数的平方根值
    produce_prime2使用筛法,筛选剔除小于等于max的所有非质数,剩下的就是质数了
2、从小到大,输出前m个质数。  筛法的速度远超普通方法,针对这个需求,普通方法很慢,筛法又不适用,因为不知道前m个质数对应的max是多少,
  这怎么办呢?质数越往后越稀疏,有个素数定理就是用来预估max以内有多少质数,最简洁的公式有x/ln(x),会有一定的误差,但是不超过百分之十五
 那么我们可以根据m反推出max的大小
"""
import math
import time
import datetime


# 最朴素的判断质数的方法, 即根据质数的定义,一直从2到该数的平方根,判断是否能整除
def produce_prime1(max_value):
    for i in range(2, max_value + 1):
        if __is_prime(i):
            print(i)
            pass


# 筛选法找质数,即“埃拉托色尼筛法”,挖掉2的倍数、3的倍数、一直到max的平方根的倍数,剩下的都是质数了
def produce_prime2(max_value):
    li = []
    for i in range(2, max_value + 1):
        if i > 2 and i % 2 == 0:
            li.append(0)
        else:
            li.append(i)

    for i in range(3, int(math.sqrt(max_value)) + 1, 2):
        if li[i - 2] != 0:
            for j in range(i + i, max_value + 1, i):
                li[j - 2] = 0

    for i in li:
        if i != 0:
            print(i)
            pass


# 从小到大,输出前count(count > 10)个质数
# 这里先使用素数定理求出count个素数分布的范围,再使用筛选法筛除所有素数,最后输出前count个素数
def produce_pre_prime(count):
    max_value = int(__find_max(count) * 1.15)
    li = []

    for i in range(2, max_value + 1):
        if i > 2 and i % 2 == 0:
            li.append(0)
        else:
            li.append(i)

    for i in range(3, int(math.sqrt(max_value)) + 1, 2):
        if li[i - 2] != 0:
            for j in range(i + i, max_value + 1, i):
                li[j - 2] = 0

    j = 0
    for i in li:
        if i != 0:
            print(i)
            j += 1
            if j >= count:
                break


# 判断number是否是质数
def __is_prime(number):
    if number <= 1:
        return False

    for i in range(2, int(math.sqrt(number)) + 1):
        if number % i == 0:
            return False

    return True


# 根据素数定理,x/ln(x) >= m 找到最小的一个整数x解,m > 10
def __find_max(m):
    if m <= 10:
        raise NameError('input illegal m <= 10!')

    start = m
    end = m * 2
    while True:
        if end / math.log(end, math.e) >= m:
            break
        start = end
        end = end * 2
    index = int((start + end) / 2)
    while True:
        m1 = index / math.log(index, math.e)
        m2 = (index - 1) / math.log(index - 1, math.e)
        if m1 >= m > m2:
            break
        if m1 >= m:
            end = index
        else:
            start = index
        index = int((start + end) / 2)

    return index


def p10(n):
    r = int(n**0.5)
    # assert r*r <= n and (r+1)**2 > n
    v_list = [n//i for i in range(1, r+1)]
    # print(v_list)
    v_list += list(range(v_list[-1]-1, 0, -1))
    # print(v_list)
    s_list = {i: i*(i+1)//2-1 for i in v_list}
    # print(s_list)
    for p in range(2, r+1):
        if s_list[p] > s_list[p-1]:  # p is prime
            sp = s_list[p-1]  # sum of primes smaller than p
            p2 = p*p
            for v in v_list:
                if v < p2:
                    break
                s_list[v] -= p*(s_list[v//p] - sp)
    return s_list[n]


# https://www.zhihu.com/question/29580448
def p10_zhihu(n):
    r = int(n**0.5)
    # assert r*r <= n and (r+1)**2 > n
    v_list = [n//i for i in range(1, r+1)]
    print(v_list)
    v_list += list(range(v_list[-1]-1, 0, -1))
    print(v_list)
    s_list = {i: i*(i+1)//2-1 for i in v_list}
    print(s_list)
    for p in range(2, r+1):
        if s_list[p] > s_list[p-1]:  # p is prime
            sp = s_list[p-1]  # sum of primes smaller than p
            p2 = p*p
            for v in v_list:
                if v < p2:
                    break
                s_list[v] -= p*(s_list[v//p] - sp)
    return s_list[n]


def main():
    # max_value = 1000000
    max_value = 10

    start = time.time() * 1000
    produce_prime1(max_value)
    end1 = time.time() * 1000
    produce_prime2(max_value)
    end2 = time.time() * 1000

    n_value = 1000000000
    print(p10_zhihu(n_value))
    end3 = time.time() * 1000

    produce_pre_prime(10000)

    print("使用质数定义法找出所有小于等于" + str(max_value) + "质数并输出,总共耗时" + str(end1 - start) + "毫秒")
    print("使用筛选法找出所有小于等于" + str(max_value) + "质数并输出,总共耗时" + str(end2 - end1) + "毫秒")
    print("计算" + str(n_value) + "内质数相加的和并输出,总共耗时" + str(end3 - end2) + "毫秒")


if __name__ == "__main__":
    print("Script start execution at %s\n\n" % str(datetime.datetime.now()))
    time_start = time.time()

    main()

    print("\n\nScript end execution at %s" % str(datetime.datetime.now()))
    print("Total Elapsed Time: %s seconds\n" % (time.time() - time_start))

results matching ""

    No results matching ""