素数筛中的分割错误

当我input一个大于46348的数字的时候运行这个程序,我得到了一个分段错误。 对于任何低于它的值,该程序完美地工作。 我在Ubuntu 10.04 64位上使用CodeBlocks 8.02。 代码如下:

int main() { int number = 46348; vector<bool> sieve(number+1,false); vector<int> primes; sieve[0] = true; sieve[1] = true; for(int i = 2; i <= number; i++) { if(sieve[i]==false) { primes.push_back(i); int temp = i*i; while(temp <= number) { sieve[temp] = true; temp = temp + i; } } } for(int i = 0; i < primes.size(); i++) cout << primes[i] << " "; return 0; } 

假设你在一个共同的架构上,问题是i*i计算溢出。 结果不能存储在一个有符号的32位整数。 你可以尝试添加cout << temp << endl; 经过这个计算。 最后它会打印:

 2144523481 2146190929 2147117569 -2146737495 Segmentation fault 

将来,您将需要在调试器中运行您的代码。 它可以让你更容易地发现这些东西。 我怀疑CodeBlocks提供了一个图形化的调试器。 (否则,请确保使用-ggdb编译并使用gdb运行程序)


由于您位于64位平台上,因此您可能希望使用64位无符号整数来获得更大的范围。 unsigned long long (C99,C ++ 0x)是一个很好的方法来要求“你得到的最大的int,这是相当便宜的”。 (即使一个long long可能跨越两个寄存器,就像IA32上的64位数据类型一样)


或者,您可以添加一个检查以在进入循环之前自动验证number < sqrt(numeric_limits<int>::max())

temp是一个32位有符号整数。 在这一行中:

 int temp = i*i; 

它计算46348*46348 = +2,148,137,104 (有符号整数的最大值是+2,147,483,647 ),它会产生一个溢出(它变成一个负数),然后尝试访问这个结果的数组:

 sieve[temp] = true; 

通过访问与负数的数组,你会得到分段错误。


(你可以把它改成unsigned int (最大值+4,294,967,295

这行:int temp = i * i; 当我大于46348时导致温度溢出,导致筛子寻找负面因素。 段错误!

用unsigned long long替换int可以让你更进一步。