📜  阿特金筛

📅  最后修改于: 2021-04-23 07:43:03             🧑  作者: Mango

在给定限制的情况下,打印所有小于或等于给定限制的素数。

例子 :

Input:  limit = 10
Output: 2, 3, 5, 7

Input:  limit = 20
Output: 2, 3, 5, 7, 11, 13, 17, 19 

我们已经讨论了上述任务的以下算法。
Eratosthenes筛
森达拉姆筛

Atkin的筛网是一种现代算法,可查找所有最大至指定整数的素数。与标出倍数质数的古代Eratosthenes筛网相比,它做了一些初步的工作,然后标出了素数平方的倍数,这就是为什么它具有更好的理论渐近复杂度,其复杂度为(N /(log log N) )

算法:

  1. 创建一个由2、3和5填充的结果列表。
  2. 创建一个筛子列表,其中每个正整数都有一个条目;此列表中的所有条目最初都应标记为非质数。
  3. 对于筛子列表中的每个条目号n,其模余数为r:
    1. 如果r为1、13、17、29、37、41、49或53,则将每种可能的解决方案的条目翻转为4x 2 + y 2 = n。
    2. 如果r为7、19、31或43,则将每个可能解的条目翻转为3x 2 + y 2 = n。
    3. 如果r为11、23、47或59,则当x> y时,将每个可能解的条目翻转为3x 2 – y 2 = n。
    4. 如果r是其他东西,请完全忽略它。
  4. 从筛号列表中的最低编号开始。
  5. 取筛子列表中的下一个仍标记为质数的数字。
  6. 在结果列表中包括数字。
  7. 将数字平方并标记该平方的所有倍数为非质数。请注意,不需要标记可以乘以2、3或5的倍数,因为在质数的最终枚举中将忽略这些倍数。
  8. 重复步骤四到七。

下面是上述算法的实现。

C++
// C++ program for implementation of Sieve of Atkin
#include 
using namespace std;
  
int SieveOfAtkin(int limit)
{
    // 2 and 3 are known to be prime
    if (limit > 2)
        cout << 2 << " ";
    if (limit > 3)
        cout << 3 << " ";
  
    // Initialise the sieve array with false values
    bool sieve[limit];
    for (int i = 0; i < limit; i++)
        sieve[i] = false;
  
    /* Mark siev[n] is true if one 
       of the following is true:
    a) n = (4*x*x)+(y*y) has odd number of 
       solutions, i.e., there exist
       odd number of distinct pairs (x, y) 
       that satisfy the equation and
        n % 12 = 1 or n % 12 = 5.
    b) n = (3*x*x)+(y*y) has odd number of 
       solutions and n % 12 = 7
    c) n = (3*x*x)-(y*y) has odd number of 
       solutions, x > y and n % 12 = 11 */
    for (int x = 1; x * x < limit; x++) {
        for (int y = 1; y * y < limit; y++) {
              
            // Main part of Sieve of Atkin
            int n = (4 * x * x) + (y * y);
            if (n <= limit && (n % 12 == 1 || n % 12 == 5))
                sieve[n] ^= true;
  
            n = (3 * x * x) + (y * y);
            if (n <= limit && n % 12 == 7)
                sieve[n] ^= true;
  
            n = (3 * x * x) - (y * y);
            if (x > y && n <= limit && n % 12 == 11)
                sieve[n] ^= true;
        }
    }
  
    // Mark all multiples of squares as non-prime
    for (int r = 5; r * r < limit; r++) {
        if (sieve[r]) {
            for (int i = r * r; i < limit; i += r * r)
                sieve[i] = false;
        }
    }
  
    // Print primes using sieve[]
    for (int a = 5; a < limit; a++)
        if (sieve[a])
            cout << a << " ";
}
  
// Driver program
int main(void)
{
    int limit = 20;
    SieveOfAtkin(limit);
    return 0;
}


Java
// Java program for implementation of Sieve
// of Atkin
class GFG {
  
    static int SieveOfAtkin(int limit)
    {
        // 2 and 3 are known to be prime
        if (limit > 2)
            System.out.print(2 + " ");
  
        if (limit > 3)
            System.out.print(3 + " ");
  
        // Initialise the sieve array with
        // false values
        boolean sieve[] = new boolean[limit];
  
        for (int i = 0; i < limit; i++)
            sieve[i] = false;
  
        /* Mark siev[n] is true if one of the
        following is true:
        a) n = (4*x*x)+(y*y) has odd number 
           of solutions, i.e., there exist 
           odd number of distinct pairs 
           (x, y) that satisfy the equation 
           and    n % 12 = 1 or n % 12 = 5.
        b) n = (3*x*x)+(y*y) has odd number 
           of solutions and n % 12 = 7
        c) n = (3*x*x)-(y*y) has odd number 
           of solutions, x > y and n % 12 = 11 */
        for (int x = 1; x * x < limit; x++) {
            for (int y = 1; y * y < limit; y++) {
  
                // Main part of Sieve of Atkin
                int n = (4 * x * x) + (y * y);
                if (n <= limit && (n % 12 == 1 || n % 12 == 5))
  
                    sieve[n] ^= true;
  
                n = (3 * x * x) + (y * y);
                if (n <= limit && n % 12 == 7)
                    sieve[n] ^= true;
  
                n = (3 * x * x) - (y * y);
                if (x > y && n <= limit && n % 12 == 11)
                    sieve[n] ^= true;
            }
        }
  
        // Mark all multiples of squares as
        // non-prime
        for (int r = 5; r * r < limit; r++) {
            if (sieve[r]) {
                for (int i = r * r; i < limit;
                     i += r * r)
                    sieve[i] = false;
            }
        }
  
        // Print primes using sieve[]
        for (int a = 5; a < limit; a++)
            if (sieve[a])
                System.out.print(a + " ");
        return 0;
    }
  
    // Driver code
    public static void main(String[] args)
    {
        int limit = 20;
        SieveOfAtkin(limit);
    }
}
  
// This code is contributed by Anant Agarwal.


Python 3
# Python 3 program for 
# implementation of 
# Sieve of Atkin
  
def SieveOfAtkin(limit):
  
    # 2 and 3 are known
    # to be prime
    if (limit > 2):
        print(2 , end = " ")
    if (limit > 3):
        print(3 , end = " ")
  
    # Initialise the sieve 
    # array with False values
    sieve = [False] * limit
    for i in range( 0 , limit ):
        sieve[i] = False
          
    '''Mark siev[n] is True if 
    one of the following is True:
    a) n = (4*x*x)+(y*y) has odd 
    number of solutions, i.e., 
    there exist odd number of 
    distinct pairs (x, y) that
    satisfy the equation and
    n % 12 = 1 or n % 12 = 5.
    b) n = (3*x*x)+(y*y) has 
    odd number of solutions 
    and n % 12 = 7
    c) n = (3*x*x)-(y*y) has 
    odd number of solutions, 
    x > y and n % 12 = 11 '''
    x = 1
    while(x * x < limit ) :
        y = 1
        while(y * y < limit ) :
              
            # Main part of 
            # Sieve of Atkin
            n = (4 * x * x) + (y * y)
            if (n <= limit and (n % 12 == 1 or 
                                n % 12 == 5)):
                sieve[n] ^= True
  
            n = (3 * x * x) + (y * y)
            if (n <= limit and n % 12 == 7):
                sieve[n] ^= True
  
            n = (3 * x * x) - (y * y)
            if (x > y and n <= limit and 
                          n % 12 == 11):
                sieve[n] ^= True
            y += 1
        x += 1
      
    # Mark all multiples of 
    # squares as non-prime
    r = 5
    while(r * r < limit) :
        if (sieve[r]) :
            for i in range(r * r, limit, r * r):
                sieve[i] = False
          
    # Print primes
    # using sieve[]
    for a in range(5 , limit ):
        if (sieve[a]):
            print(a , end = " ")
  
# Driver Code
limit = 20
SieveOfAtkin(limit)
  
# This code is contributed
# by Smitha


C#
// C# program for implementation of Sieve
// of Atkin
using System;
  
class GFG {
  
    static int SieveOfAtkin(int limit)
    {
        // 2 and 3 are known to be prime
        if (limit > 2)
            Console.Write(2 + " ");
  
        if (limit > 3)
            Console.Write(3 + " ");
  
        // Initialise the sieve array with
        // false values
        bool[] sieve = new bool[limit];
  
        for (int i = 0; i < limit; i++)
            sieve[i] = false;
  
        /* Mark siev[n] is true if one of the
        following is true:
        a) n = (4*x*x)+(y*y) has odd number 
           of solutions, i.e., there exist 
           odd number of distinct pairs 
           (x, y) that satisfy the equation 
           and    n % 12 = 1 or n % 12 = 5.
        b) n = (3*x*x)+(y*y) has odd number 
           of solutions and n % 12 = 7
        c) n = (3*x*x)-(y*y) has odd number 
           of solutions, x > y and n % 12 = 11 */
        for (int x = 1; x * x < limit; x++) {
            for (int y = 1; y * y < limit; y++) {
  
                // Main part of Sieve of Atkin
                int n = (4 * x * x) + (y * y);
                if (n <= limit && (n % 12 == 1 || n % 12 == 5))
  
                    sieve[n] ^= true;
  
                n = (3 * x * x) + (y * y);
                if (n <= limit && n % 12 == 7)
                    sieve[n] ^= true;
  
                n = (3 * x * x) - (y * y);
                if (x > y && n <= limit && n % 12 == 11)
                    sieve[n] ^= true;
            }
        }
  
        // Mark all multiples of squares as
        // non-prime
        for (int r = 5; r * r < limit; r++) {
            if (sieve[r]) {
                for (int i = r * r; i < limit;
                     i += r * r)
                    sieve[i] = false;
            }
        }
  
        // Print primes using sieve[]
        for (int a = 5; a < limit; a++)
            if (sieve[a])
                Console.Write(a + " ");
        return 0;
    }
  
    // Driver code
    public static void Main()
    {
        int limit = 20;
        SieveOfAtkin(limit);
    }
}
  
// This code is contributed by nitin mittal


PHP
 2)
        echo 2 , " ";
    if ($limit > 3)
        echo 3 , " ";
  
    // Initialise the sieve array 
    // with false values
    $sieve[$limit] = 0;
    for ($i = 0; $i < $limit; $i++)
        $sieve[$i] = false;
  
    /* Mark siev[n] is true if one 
       of the following is true:
    a) n = (4*x*x)+(y*y) has odd number of 
       solutions, i.e., there exist
       odd number of distinct pairs (x, y) 
       that satisfy the equation and
       n % 12 = 1 or n % 12 = 5.
    b) n = (3*x*x)+(y*y) has odd number of 
       solutions and n % 12 = 7
    c) n = (3*x*x)-(y*y) has odd number of 
       solutions, x > y and n % 12 = 11 */
    for ($x = 1; $x * $x < $limit; $x++)
    {
        for ($y = 1; $y * $y < $limit; $y++) 
        {
              
            // Main part of Sieve of Atkin
            $n = (4 * $x * $x) + ($y * $y);
            if ($n <= $limit && ($n % 12 == 1 || 
                                   $n % 12 == 5))
                $sieve[$n] ^= true;
  
            $n = (3 * $x * $x) + ($y * $y);
            if ($n <= $limit && $n % 12 == 7)
                $sieve[$n] = true;
  
            $n = (3 * $x * $x) - ($y * $y);
            if ($x > $y && $n <= $limit &&
                            $n % 12 == 11)
                $sieve[$n] ^= true;
        }
    }
  
    // Mark all multiples of
    // squares as non-prime
    for ($r = 5; $r * $r < $limit; $r++) {
        if ($sieve[$r]) {
            for ($i = $r * $r; $i < $limit;
                             $i += $r * $r)
                $sieve[$i] = false;
        }
    }
  
    // Print primes 
    // using sieve[]
    for ($a = 5; $a < $limit; $a++)
        if ($sieve[$a])
            echo $a , " ";
}
  
    // Driver Code
    $limit = 20;
    SieveOfAtkin($limit);
  
// This code is contributed by nitin mittal.
?>


输出:

2 3 5 7 11 13 17 19 

这个怎么运作:

  1. 该算法将2、3和5视为特殊情况,并将它们添加到素数集开始。
  2. 像Eratosthenes的Sieve一样,我们从要调查的数字列表开始。假设我们要查找质数<= 100,然后为[5,100]列出一个列表。如(1)中所述,2、3和5是特殊情况,而4不是质数。
  3. 该算法根据60模余数进行运算。 。
  4. 模数余数为1、13、17、29、37、41、49或53的所有数字的模数十二为1或5的余数。当且仅当解数为4×2时,这些数为质数。 + y2 = n为奇数,数字为无平方。平方自由整数是不能被除1以外的任何理想平方整除的整数。
  5. 模数余数为7、19、31或43的所有数字的模数余数均为1。当且仅当对3x 2 + y 2 = n的解数为奇数且该数为时,这些数为质数。不占空间的。
  6. 所有具有模六十余数11、23、47或59的数均具有11的模十二余数。当且仅当对3x 2 – y 2 = n的解数为奇数且该数为时,这些数为质数。不占空间的。

让我们看看它如何生成最高达20的素数:

1    2    3    4    5    6    7    8    9    10
11  12   13    14   15   16   17  18   19    20

步骤0:
开始时所有数字的状态为False。特殊数字是2、3和5,它们是素数。

步骤1:
生成条件的值。
阿特金斯

第2步:
根据条件翻转状态。

将对x,y循环中生成的表中的n的上述值进行模条件测试。
第1列: if(colum1值)%12 == 1或5
然后翻转该数字的筛分状态。
我们采用12代替60的mod,这是因为如果采用mod 60,则必须将许多r视为1、13、17、29、37、41、49或53,对于所有这些r,mod 12为1或5。(仅执行此操作可减小表达式的大小)

第2列: if(colum2值)%12 == 7
然后翻转该数字的筛分状态。

第3列: if(colum3值)%12 == 11
然后翻转该数字的筛分状态。

第三步:
检查无方形情况:如果我们列表中的任何数字都位于任何数字的正方形中,则将其删除。

第四步 :
创建素数数组,其状态为true。
即2 3 5 7 11 13 17 19

第五步:
在屏幕上打印输出。

资料来源:
https://zh.wikipedia.org/wiki/Sieve_of_Atkin
http://primesieve.org/
http://www.ams.org/journals/mcom/2004-73-246/S0025-5718-03-01501-1/S0025-5718-03-01501-1.pdf