这是我在C中筛选eratosthenes的代码。 它给了我以下输出。
2 3 五 7 11 13 17 19 23 25 31 35 37 41 43 47
我的输出包括25和35也不是素数,它不包括29。
谁能告诉我哪里错了。
#include<stdio.h>
#include<math.h>
int main()
{
int i,a[50],b[50],j,n=0,s;
for(i=0;i<50;i++)
a[i] = 1;
a[0]=a[1] = 0;
for(i=2;i<50;i++)
if(a[i])
for(j=pow(i,2);j<50;j+=i)
a[j] = 0;
for(i=0;i<50;i++)
if(a[i])
{
b[n] = i;
n++;
}
for(j=0;j<n;j++)
printf("%d\n",b[j]);
return 0;
}
答案 0 :(得分:6)
使用gcc版本4.4.7(Ubuntu / Linaro 4.4.7-2ubuntu1)编译,您的代码返回正确的结果。该问题可能与编译器和pow()
实现有关。
可能您有pow
的天真实施,将pow(x,y)
计算为exp(y*log(x))
。这是浮点运算,它遇到常见的浮点问题。这意味着pow(x,y)
转换为整数的结果将被截断,因为双重算术log(x)*y
和取幂将返回略小于整数x*y
的double值。
将代码更改为
for( j = i * i; j < 50; j += i)
a[j] = 0;
此外,我们只能迭代直到sqrt(n),因为第二个循环才会被执行:
for( i = 2; i < sqrt(50); i++)
if( a[i]) // if not marked
/* mark starting from i*i because i*j for j<i
* has been already marked when i was j */
for( j = i * i; j < 50; j += i)
a[j] = 0;
答案 1 :(得分:4)
正如其他人所观察到的那样,错误发生在pow
函数中。我无法使用您显示的代码重现您的错误,但是当我推出自己的ppow
函数时:
double ppow(double a, double x)
{
return exp(log(a) * x);
}
我的名单与你的名单相符。我认为pow
的符合标准的实现应该将整数指数视为可以采用负基的特殊情况,因此pow
似乎不符合。
而不是pow(i, 2)
,请使用i*i
。这应该更快,你也不必链接到数学库。
答案 2 :(得分:2)
我尝试重现你的输出,但我不能。
操作系统信息:
$ uname -a Linux 3.13.0-29-generic#53-Ubuntu SMP Wed Jun 4 21:00:20 UTC 2014 x86_64 x86_64 x86_64 GNU / Linux
编译器信息:
$ gcc --version gcc(Ubuntu 4.8.2-19ubuntu1)4.8.2
编译:
$ gcc sieve_of_eratosthenes.c -lm -o sieve_of_eratosthenes
启动:
$ ./sieve_of_eratosthenes
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
答案 3 :(得分:0)
当pow
函数使用处理器上的浮点单元时,它可能会产生异常。
在执行此函数期间发生此类异常时,可能会返回不正确的值。
当您pow(i,2)
与i
等于5
时,系统可能就是这种情况。
作为支持这一猜想的间接证据,请注意每个数字(在[0-49]的指定范围内)是 5和素数大于5 的倍数,在你的素数列表上。
以下是一段代码,用于检索因FP操作而可能发生的异常:
#include <fenv.h>
#include <stdio.h>
void print_fe_exceptions()
{
printf("Exceptions raised:");
if (fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO");
if (fetestexcept(FE_INEXACT )) printf(" FE_INEXACT ");
if (fetestexcept(FE_INVALID )) printf(" FE_INVALID ");
if (fetestexcept(FE_OVERFLOW )) printf(" FE_OVERFLOW ");
if (fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW");
feclearexcept(FE_ALL_EXCEPT);
printf("\n");
}
以下是每个例外情况的描述:
FE_DIVBYZERO // Pole error occurred in an earlier floating-point operation
FE_INEXACT // Inexact result: rounding was necessary to store the result of an earlier floating-point operation
FE_INVALID // Domain error occurred in an earlier floating-point operation
FE_OVERFLOW // The result of an earlier floating-point operation was too large to be representable
FE_UNDERFLOW // The result of an earlier floating-point operation was subnormal with a loss of precision