【问题标题】:Intitutive method to find prime numbers in a range在一个范围内查找素数的直观方法
【发布时间】:2015-09-26 18:16:23
【问题描述】:

在尝试查找某个范围内的质数时(请参阅problem description),我遇到了以下代码:

(代码取自here

// For each prime in sqrt(N) we need to use it in the segmented sieve process.
for (i = 0; i < cnt; i++) {
    p = myPrimes[i]; // Store the prime.
    s = M / p;
    s = s * p; // The closest number less than M that is composite number for this prime p.

    for (int j = s; j <= N; j = j + p) {
        if (j < M) continue; // Because composite numbers less than M are of no concern.

        /* j - M = index in the array primesNow, this is as max index allowed in the array
           is not N, it is DIFF_SIZE so we are storing the numbers offset from.
           while printing we will add M and print to get the actual number. */
        primesNow[j - M] = false;
    }
}

// In this loop the first prime numbers for example say 2, 3 are also set to false.
for (int i = 0; i < cnt; i++) { // Hence we need to print them in case they're in range.
    if (myPrimes[i] >= M && myPrimes[i] <= N) // Without this loop you will see that for a
                                              // range (1, 30), 2 & 3 doesn't get printed.
        cout << myPrimes[i] << endl;
}

// primesNow[] = false for all composite numbers, primes found by checking with true.
for (int i = 0; i < N - M + 1; ++i) {
    // i + M != 1 to ensure that for i = 0 and M = 1, 1 is not considered a prime number.
    if (primesNow[i] == true && (i + M) != 1)
        cout << i + M << endl; // Print our prime numbers in the range.
}

但是,我发现这段代码并不直观,而且不容易理解。

  • 有人能解释一下上述算法背后的总体思路吗?
  • 有哪些替代算法可以标记范围内的非质数?

【问题讨论】:

  • 基本原理很简单;一旦你找到一个素数,这个数的所有倍数都不是素数。

标签: c++ primes sieve-of-eratosthenes


【解决方案1】:

这太复杂了。让我们从一个基本的埃拉托色尼筛法开始,用伪代码输出所有小于或等于 n 的素数:

function primes(n)
    sieve := makeArray(2..n, True)
    for p from 2 to n
        if sieve[p]
            output(p)
            for i from p*p to n step p
                sieve[p] := False

这个函数在每个素数p上调用outputoutput 可以打印素数,或对素数求和,或对它们进行计数,或对它们做任何你想做的事情。外部for 循环依次考虑每个候选素数;筛分发生在内部 for 循环中,其中当前素数 p 的倍数从筛子中移除。

了解其工作原理后,请转至 here 讨论在一定范围内的分段埃拉托色尼筛。

【讨论】:

    【解决方案2】:

    您是否在位级别上考虑过筛子,它可以提供更多的素数,并且使用缓冲区,您可以修改它以使用 64 位整数查找例如 2 到 2^60 之间的素数,通过重用相同的缓冲区,同时保留已发现的素数的偏移量。以下将使用整数数组。

    声明

    #include <math.h>         // sqrt(), the upper limit need to eliminate
    #include <stdio.h>        // for printing, could use <iostream>
    

    来操作位,以下将使用32位整数

    #define BIT_SET(d, n)   (d[n>>5]|=1<<(n-((n>>5)<<5)))      
    #define BIT_GET(d, n)   (d[n>>5]&1<<(n-((n>>5)<<5)))
    #define BIT_FLIP(d, n)  (d[n>>5]&=~(1<<(n-((n>>5)<<5))))
    
    unsigned int n = 0x80000;   // the upper limit 1/2 mb, with 32 bits each 
                                // will get the 1st primes upto 16 mb    
    int *data = new int[n];     // allocate
    unsigned int r = n * 0x20;  // the actual number of bits avalible
    

    可以使用零来节省时间但是,对于素数来说,(1) 更直观

    for(int i=0;i<n;i++)
        data[i] = 0xFFFFFFFF;
    
    unsigned int seed = 2;           // the seed starts at 2  
    unsigned int uLimit = sqrt(r);   // the upper limit for checking off the sieve
    
    BIT_FLIP(data, 1);      // one is not prime
    

    发现质数的时间不到半秒

    // untill uLimit is reached
    while(seed < uLimit) {
        // don't include itself when eliminating canidates
        for(int i=seed+seed;i<r;i+=seed) 
            BIT_FLIP(data, i);
    
        // find the next bit still active (set to 1), don't include the current seed
        for(int i=seed+1;i<r;i++) {
            if (BIT_GET(data, i)) {
                seed = i;
                break;
            }
        }
    }
    

    现在输出这将消耗最多的时间

    unsigned long bit_index = 0;      // the current bit
    int w = 8;                        // the width of a column
    unsigned pc = 0;                  // prime, count, to assist in creating columns
    
    for(int i=0;i<n;i++) {
        unsigned long long int b = 1;  // double width, so there is no overflow
    
        // if a bit is still set, include that as a result
    
        while(b < 0xFFFFFFFF) {
            if (data[i]&b) {
                printf("%8.u ", bit_index);
                if(((pc++) % w) == 0)
                    putchar('\n');   // add a new row                
            }
    
            bit_index++;
            b<<=1;                       // multiply by 2, to check the next bit    
        }
    
    }
    

    清理

    delete [] data;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-23
      • 2018-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多