我在维基百科上读到了有关Atkin筛的内容,但目前维基百科的内容还比较有限。我在寻找一个高层次的Atkin筛解释,并附带一个Java示例。
谢谢。
我在维基百科上读到了有关Atkin筛的内容,但目前维基百科的内容还比较有限。我在寻找一个高层次的Atkin筛解释,并附带一个Java示例。
谢谢。
// SieveOfAtkin.java
import java.util.Arrays;
public class SieveOfAtkin {
private static int limit = 1000;
private static boolean[] sieve = new boolean[limit + 1];
private static int limitSqrt = (int)Math.sqrt((double)limit);
public static void main(String[] args) {
// there may be more efficient data structure
// arrangements than this (there are!) but
// this is the algorithm in Wikipedia
// initialize results array
Arrays.fill(sieve, false);
// the sieve works only for integers > 3, so
// set these trivially to their proper values
sieve[0] = false;
sieve[1] = false;
sieve[2] = true;
sieve[3] = true;
// loop through all possible integer values for x and y
// up to the square root of the max prime for the sieve
// we don't need any larger values for x or y since the
// max value for x or y will be the square root of n
// in the quadratics
// the theorem showed that the quadratics will produce all
// primes that also satisfy their wheel factorizations, so
// we can produce the value of n from the quadratic first
// and then filter n through the wheel quadratic
// there may be more efficient ways to do this, but this
// is the design in the Wikipedia article
// loop through all integers for x and y for calculating
// the quadratics
for (int x = 1; x <= limitSqrt; x++) {
for (int y = 1; y <= limitSqrt; y++) {
// first quadratic using m = 12 and r in R1 = {r : 1, 5}
int n = (4 * x * x) + (y * y);
if (n <= limit && (n % 12 == 1 || n % 12 == 5)) {
sieve[n] = !sieve[n];
}
// second quadratic using m = 12 and r in R2 = {r : 7}
n = (3 * x * x) + (y * y);
if (n <= limit && (n % 12 == 7)) {
sieve[n] = !sieve[n];
}
// third quadratic using m = 12 and r in R3 = {r : 11}
n = (3 * x * x) - (y * y);
if (x > y && n <= limit && (n % 12 == 11)) {
sieve[n] = !sieve[n];
} // end if
// note that R1 union R2 union R3 is the set R
// R = {r : 1, 5, 7, 11}
// which is all values 0 < r < 12 where r is
// a relative prime of 12
// Thus all primes become candidates
} // end for
} // end for
// remove all perfect squares since the quadratic
// wheel factorization filter removes only some of them
for (int n = 5; n <= limitSqrt; n++) {
if (sieve[n]) {
int x = n * n;
for (int i = x; i <= limit; i += x) {
sieve[i] = false;
} // end for
} // end if
} // end for
// put the results to the System.out device
// in 10x10 blocks
for (int i = 0, j = 0; i <= limit; i++) {
if (sieve[i]) {
System.out.printf("%,8d", i);
if (++j % 10 == 0) {
System.out.println();
} // end if
if (j % 100 == 0) {
System.out.println();
} // end if
} // end if
} // end for
} // end main
} // end class SieveOfAtkin
{一些列举的集合或定义其中一个的属性}
表示一个集合;Nat0
表示包括零在内的自然数集合,即Nat0 = {0, 1, 2, ...};Nat
表示不包括零的自然数集合,即Nat = {1, 2, 3, ...},以及以下构造用于定义集合和其中一个元素的符号:{集合中元素的符号:通过该符号定义集合的条件}
#
表示集合基数,即集合中元素的数量;^
表示乘方,即x的平方写作x^2。n = (k * m) + r,其中k属于Nat0,r属于R = {r: r属于Nat0且r
n mod m = r,其中r属于R = {r: r属于Nat0且r
以下是论文中定理给出的定义以及一些关于模算术形式的注释:
当n除以12的余数为r,其中r属于R2a = {r : 1, 7}时:
n mod 60 = r,其中r属于R2b = {r : 1, 7, 13, 19, 25, 31, 37, 43, 49, 55}。
同样,集合R2a和R2b中的值可以因为后面将要解释的两个原因而被删除,但定理依旧适用。
对于第三个二次方程,(3 * x^2) - (y^2):
该定理使用以下形式:
n = k * 12 + r,其中k为自然数0,r属于R3a = {r : 11}。
同样,这等同于:
n mod 12 = r,其中r属于R3a = {r : 11}。
请注意,这是从11开始的自然数奇数序列中每六个数字中的一个,即{11、23、35、47、...}。
在论文和文章中等效的n为:
n mod 60 = r,其中r属于R3b = {r : 11, 23, 35, 47, 59}。
同样,集合R3b中的值可以因为后面将要解释的原因而被删除,但定理依旧适用。
在各种算法和解释中,对于m = 12和m = 60的值,可以删除集合R的元素,而不影响定理或算法的有效性。一些值在集合R中被抛弃的原因有两个。
第一个原因是,如果集合R中的任何r值与其配对的m不互质,则只会包括具有一个或多个m的素因子的复合整数n,其中没有一个是素数。这种模运算的特点是,轮筛法可用于从进一步检测是否是素数的大量非素数中过滤出来,通常需要更复杂且效率较低的测试。在此筛法中,更复杂的测试是特定不可约二次方程的解数是否为奇数。这意味着我们可以立即丢弃该算法中集合R中与使用该集合R的m值不互质的所有值。
第二个原因是,在文献中,轮子分解会创建重叠的整数集,包括重叠素数。虽然它们很方便,而且在定理中重叠并不重要,但在算法中,如果能够轻松避免重叠,则是浪费的。在这种情况下,可以轻松地避免。另外,如果来自轮子分解的整数集重叠,则一个二次方程中的奇数解的数量加上另一个二次方程中的奇数解的数量将变成累计偶数解(奇数加奇数始终是偶数)。在许多实现中,包括维基百科实现,这将确定质数不是质数,因为类似维基百科这样的实现从所有二次方程的累积解来确定质性,并且不将每个二次方程的解隔离。在这些情况下,从轮子分解中获取的整数必须是互斥的子集,这是至关重要的。