【问题标题】:Why doesn't my code generate the prime numbers correctly为什么我的代码不能正确生成素数
【发布时间】:2014-11-04 12:24:04
【问题描述】:

小于 10,000,000 的素数数量为 664,579,但我的代码仅生成 664,214。号码来源https://primes.utm.edu/howmany.html

#include <iostream>
#include <bitset>
#include <vector>
using namespace std;

const int N = 10000001;
bitset<N>num;
vector<int>prime;
inline void sieve()
{
    num.flip();
    num[0] = num[1] = 0;
    for(int i=2;i<N;i++)
        if(num[i])
        {
            prime.push_back(i);
            for(long long unsigned j=i*i; j<N;j+=i)
                num[j] = 0;
        }
}

int main() {
    sieve();
    cout << prime.size() << endl;
    return 0;
}

【问题讨论】:

    标签: c++ primes sieve


    【解决方案1】:

    计算i*i 时出现整数溢出。然后将结果分配给 long long 的事实不会使编译器在乘法之前提升类型。

    如果我将i 声明为long long unsigned int,那么您的程序输出 664579

    【讨论】:

    • 如果j的初始化改成j=(unsigned long long)i*i,也会打印出正确的输出。
    • 如果外部循环的限制设置正确(到 sqrt(N)),那么乘法一开始就永远不会溢出。这不仅是尽职调查,它还将外部循环的迭代次数减少到一小部分。注意:根据舍入模式,sqrt() 可以向上舍入而不是向下舍入;最好写一个小函数max_factor() 来处理血淋淋的细节并且可以单独测试。
    • 对于一般的筛选代码,如果使用正确的数据类型(无符号整数),边界情况的数量会大大减少,如果使用打包(仅奇数)位图则更是如此,因为这会购买索引变量中的额外空间。在一个问题上不必要地抛出双宽整数不是一种可能产生良好和健壮代码的策略。除了鼓励智力上的懒惰之外,它还倾向于使代码变得更混乱而不是更好。
    • 在进入内部for 循环之前最好检查i &lt;= N/i。那么int j就OK了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 1970-01-01
    • 2018-12-03
    • 1970-01-01
    相关资源
    最近更新 更多