📜  分段筛(1)

📅  最后修改于: 2023-12-03 15:07:09.555000             🧑  作者: Mango

分段筛

分段筛是一种优化算法,通常应用于大质数筛法中,其主要思想是根据质数的性质,对待筛区间进行适当分段,每段内只包含小于等于段内最大数平方根的质数,从而避免冗余计算。

具体实现
步骤1:对待筛区间进行分段

以区间 [1,1000] 为例,分段的具体操作如下:

import math

start = 1
end = 1000
segment = math.isqrt(end)  # 取区间终点的平方根作为段内最大值

for i in range(start, end+1, segment):
    # 对区间逐段处理
    segment_end = min(i+segment-1, end)
    print(f"[{i},{segment_end}]")

以上代码执行结果:

[1,31]
[32,62]
[63,93]
[94,100]

其中,以区间终点的平方根作为段内最大值的原因是,如果待筛数值大于段内最大值,则肯定已经被筛过,无需再次计算。

步骤2:对每个段内的质数进行标记
is_prime = [True] * (end+1)  # 默认所有数都是质数
is_prime[0] = False  # 0和1不是质数
is_prime[1] = False

for i in range(start, end+1, segment):
    segment_end = min(i+segment-1, end)
    for j in range(2, math.isqrt(segment_end)+1):
        # 标记每个段内的质数
        if is_prime[j]:
            for k in range(max(j*2, (i+j-1)//j*j), segment_end+1, j):
                is_prime[k] = False

以上代码会将区间 [1,1000] 内所有质数标记为 True,其余数值标记为 False。

步骤3:输出质数
for i in range(start, end+1):
    if is_prime[i]:
        print(i)

输出结果为区间 [1,1000] 内的所有质数:

2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
注意事项
  • 分段内的最大质数应不大于段内最大值的平方根
  • 对于所有数值的数组,建议使用布尔类型
  • 在实现时,需尽可能利用已筛出的质数
  • 可以使用多线程或多进程加速计算
示例代码
import math

def segmented_sieve(start, end):
    segment = math.isqrt(end)
    is_prime = [True] * (end+1)
    is_prime[0] = False
    is_prime[1] = False

    for i in range(start, end+1, segment):
        segment_end = min(i+segment-1, end)
        for j in range(2, math.isqrt(segment_end)+1):
            if is_prime[j]:
                for k in range(max(j*2, (i+j-1)//j*j), segment_end+1, j):
                    is_prime[k] = False

    primes = []
    for i in range(start, end+1):
        if is_prime[i]:
            primes.append(i)

    return primes

if __name__ == '__main__':
    start = 1
    end = 1000
    primes = segmented_sieve(start, end)

    print(f"Segmented sieve from {start} to {end}:")
    print(primes)

以上代码将输出区间 [1,1000] 内的所有质数:

Segmented sieve from 1 to 1000:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

返回markdown格式

分段筛

分段筛是一种优化算法,通常应用于大质数筛法中,其主要思想是根据质数的性质,对待筛区间进行适当分段,每段内只包含小于等于段内最大数平方根的质数,从而避免冗余计算。

具体实现
步骤1:对待筛区间进行分段

以区间 [1,1000] 为例,分段的具体操作如下:

import math

start = 1
end = 1000
segment = math.isqrt(end)  # 取区间终点的平方根作为段内最大值

for i in range(start, end+1, segment):
    # 对区间逐段处理
    segment_end = min(i+segment-1, end)
    print(f"[{i},{segment_end}]")

以上代码执行结果:

[1,31]
[32,62]
[63,93]
[94,100]

其中,以区间终点的平方根作为段内最大值的原因是,如果待筛数值大于段内最大值,则肯定已经被筛过,无需再次计算。

步骤2:对每个段内的质数进行标记
is_prime = [True] * (end+1)  # 默认所有数都是质数
is_prime[0] = False  # 0和1不是质数
is_prime[1] = False

for i in range(start, end+1, segment):
    segment_end = min(i+segment-1, end)
    for j in range(2, math.isqrt(segment_end)+1):
        # 标记每个段内的质数
        if is_prime[j]:
            for k in range(max(j*2, (i+j-1)//j*j), segment_end+1, j):
                is_prime[k] = False

以上代码会将区间 [1,1000] 内所有质数标记为 True,其余数值标记为 False。

步骤3:输出质数
for i in range(start, end+1):
    if is_prime[i]:
        print(i)

输出结果为区间 [1,1000] 内的所有质数:

2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
注意事项
  • 分段内的最大质数应不大于段内最大值的平方根
  • 对于所有数值的数组,建议使用布尔类型
  • 在实现时,需尽可能利用已筛出的质数
  • 可以使用多线程或多进程加速计算
示例代码
import math

def segmented_sieve(start, end):
    segment = math.isqrt(end)
    is_prime = [True] * (end+1)
    is_prime[0] = False
    is_prime[1] = False

    for i in range(start, end+1, segment):
        segment_end = min(i+segment-1, end)
        for j in range(2, math.isqrt(segment_end)+1):
            if is_prime[j]:
                for k in range(max(j*2, (i+j-1)//j*j), segment_end+1, j):
                    is_prime[k] = False

    primes = []
    for i in range(start, end+1):
        if is_prime[i]:
            primes.append(i)

    return primes

if __name__ == '__main__':
    start = 1
    end = 1000
    primes = segmented_sieve(start, end)

    print(f"Segmented sieve from {start} to {end}:")
    print(primes)

以上代码将输出区间 [1,1000] 内的所有质数:

Segmented sieve from 1 to 1000:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]