【问题标题】:Printing prime numbers from x to y algorithm打印从 x 到 y 算法的素数
【发布时间】:2014-10-29 12:53:12
【问题描述】:

我有这个 sn-p 代码,它可以在足够长的时间内使用埃拉托色尼筛法在“max”上生成素数。

我想为函数提供使用起始值来计算素数范围的可能性。所以我想知道在算法中的什么时候我必须交出起始值..

例如

get_primes(unsigned long from, unsigned long to);
get_primes(200, 5000);

-> 将 200 到 5000 的素数保存在向量中。

很遗憾,我并不完全理解算法。 [特别是第 3 到 5、7 和 10 行不清楚]

我尝试使用调试器按照这些步骤进行操作,但这并没有让我变得更聪明。

如果有人能更好地向我解释这段代码并告诉我如何设置起始值,那就太好了。

谢谢。

vector<unsigned long long> get_primes(unsigned long max) {
    vector<unsigned long long> primes;
    char *sieve;
    sieve = new char[max / 8 + 1];
    memset(sieve, 0xFF, (max / 8 + 1) * sizeof(char));
    for (unsigned long long x = 2; x <= max; x++)
        if (sieve[x / 8] & (0x01 << (x % 8))) {
            primes.push_back(x);
            for (unsigned long long j = 2 * x; j <= max; j += x)
                sieve[j / 8] &= ~(0x01 << (j % 8));
        }
    delete[] sieve;
    return primes;
}

【问题讨论】:

  • char *sieve 用作大位域。
  • 从循环中删除primes.push_back(x);;之后在筛子上迭代你的间隔。您不理解的部分使用“聪明”的位移将八个标志位存储在char(应该是无符号的)中。
  • 你可能会喜欢我对 Eratosthenes 分段筛的解释:http://stackoverflow.com/questions/10249378/segmented-sieve-of-eratosthenes
  • 你描述的是一个offset sieve of Eratosthenes(伪代码并链接到那里的C代码) - 你在其中筛选一个高达sqrt(y)的核心,以及来自@的一个附加段987654330@ 到 y 使用核心中的素数。 “分段”筛指的是不断发现素数,一段接一段。

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


【解决方案1】:

您必须从 2 开始,因为 筛子 首先删除所有 2 的倍数以找到下一个质数为 3。然后它删除所有 3 的倍数以找到下一个质数为 5 并且以此类推

【讨论】:

  • @chux 谢谢 - 没有意识到这一点并解释了为什么以前会发生这种情况!
  • 埋在你参加 2013 Informed Badge 的 2 分钟游览中](stackoverflow.com/help/badges/2600/informed)。但是,唉,我也有同样的问题。 ;-)
【解决方案2】:

如果您想使用 get_primes() 版本生成无符号长长素数,那么您需要等待很长时间。

为了生成 lo ... hi(含)范围内的素数,您只需要考虑到 sqrt(hi) 的因子。因此,您需要一个小筛子(最多 32 位)来筛选因子和另一个大小为 (hi - lo + 1) 的小筛子来筛选目标范围。

这是一个筛子的缩略版,它的筛分范围为 2^64 - 1;它使用完整的筛子而不是仅筛分奇数,因为它是我用来验证优化实现的参考代码。对此的更改很简单,但给整个shebang增加了更多的陷阱。因为它在大约 3 秒内筛选出 999560010209 和 999836351599 之间的 1000 万个素数,在大约 20 秒内筛选出 18446744073265777349u 和 18446744073709551557u 之间的 1000 万个素数(即略低于 2^64)

因子筛选器是全局性的,因为它经常被重复使用,并且筛选因子也可能需要一段时间。 IE。为接近 2^64 的范围准备因子意味着筛选所有(或大部分)因子,直到 2^32 - 1,因此它可能很容易花费 10 秒。

我将位图代码(道德上等同于 std::bitset)和因子筛分到类中;使用原始向量会使代码不灵活且不可读。为了说明起见,我缩短了我的代码,删除了许多断言和其他噪音,并用内联代码替换了对外部函数的调用(比如对 std::sqrt() 的调用)。这样您就可以直接从经过验证的工作代码中挑选出诸如如何处理偏移量(此处称为 lo)之类的答案。

将 number_t 和 index_t 分开的意义在于 number_t 可以是 unsigned long long 但对于我当前的基础架构, index_t 必须是 uint32_t。 bitmap_t 的成员函数使用底层 CPU 指令的名称。 BTS ... 位测试和设置,BT ... 位测试。位图初始化为 0,设置位表示非素数。

typedef uint32_t index_t;
sieve_t g_factor_sieve;

template<typename number_t, typename OutputIterator>
index_t generate_primes (number_t lo, number_t hi, OutputIterator sink)
{
   // ...

   index_t max_factor = index_t(std::sqrt(double(hi)));

   g_factor_sieve.extend_to_cover(max_factor);

   number_t range = hi - lo;  assert( range <= index_t(index_t(0) - 1) );
   index_t range32 = index_t(range);
   bitmap_t bm(range32);

   if (lo <  2)  bm.bts(1 - index_t(lo));   // 1 is not a prime
   if (lo == 0)  bm.bts(0);                 // 0 is not a prime

   for (index_t n = 2; n <= max_factor && n > 1; n += 1 + (n & 1))
   {
      if (g_factor_sieve.not_prime(n))  continue;

      number_t start = square(number_t(n));
      index_t stride = n << (int(n) > 2 ? 1 : 0);  // double stride for n > 2

      if (start >= lo)
         start -= lo;
      else
         start = (stride - (lo - start) % stride) % stride;

      // double test because of the possibility of wrapping
      for (index_t i = index_t(start); i <= bm.max_bit; )
      {
         bm.bts(i);

         if ((i += stride) < stride)
         {
            break;
         }
      }
   }

   // output

   for (index_t i = 0; ; ++i)
   {
      if (!bm.bt(i))
      {
         *sink = lo + i;

         ++sink;  
         ++n;
      }

      if (i >= bm.max_bit)  break;
   }

   return n;
}

【讨论】:

  • 我以范围 999560010209 ... 999836351599 为例,因为这是可以从 primos.mat.br 下载的最后一个完整的 1000 万个质数批次;最后一批(999836351609 到 999999999989)仅包含 590 万个素数。
【解决方案3】:

试试这个; 我用它来设置开始和结束的数字

for(int x = m;x<n;x++){
    if(x%2!=0 && x%3!=0 && x%5!=0 && x%7!=0 && x%11!=0)
      // then x is prime
}

其中 m 是起始值,n 是结束值

【讨论】:

  • 13 怎么样?不是素数吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-17
  • 2013-09-01
  • 1970-01-01
  • 2023-04-06
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多