【问题标题】:sieve of eratosthenes in c [closed]c中的eratosthenes筛[关闭]
【发布时间】:2014-06-09 11:44:10
【问题描述】:

这是我用 C 语言进行 Eratosthenes 筛分的代码。 它给了我以下输出。

2 3 5 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;
}

【问题讨论】:

  • 我无法重现该错误。也许你对pow() 有不同的实现。请改用i*i
  • 对我来说也一样。请指定编译器版本和更多环境细节。
  • 并且在没有优化标志的情况下编译(如果 gcc)
  • 请指定编译器
  • 不相关,但我建议使用比ab 更具描述性的变量名称。

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


【解决方案1】:

使用 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 略小的双精度值。

把代码改成

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; 

相关问题:code blocks power function is not working in c

【讨论】:

  • i2 时,2*i 已被标记为非质数。对于3*i4*i 等也是如此。从i*i 开始就足够了。
  • @bits_international 仍然不能解决 SO 问题。事实上,我们正在处理一些其他问题而不是算法问题。
  • 是的,代码块的 pow 实现是问题所在。感谢您的链接。
  • 我为您服务,我的好先生
【解决方案2】:

正如其他人所观察到的,错误出现在 pow 函数中。我无法使用您显示的代码重现您的错误,但是当我推出自己的 ppow 函数时:

double ppow(double a, double x)
{
    return exp(log(a) * x);
}

我的列表与你的一致。我认为pow 的符合标准的实现应该将整数指数视为可以采用负基数的特殊情况,因此您的pow 似乎不符合标准。

使用i*i 代替pow(i, 2)。那应该会更快,而且您也不必链接到数学库。

【讨论】:

  • 谢谢,使用 i*i 代替 pow(i,2) 解决了我的问题,但我仍然不明白为什么 pow(i,2) 给了我错误的答案。
  • pow 适用于浮点数。它们并不精确,当它们是上述ppow 实现中的计算结果时更是如此。对于ppow(20, 2),我得到 399.9999999999999,例如,在转换为 int 后将变为 399。你可能会舍弃舍入:ppow(i, 2) + 0.5,但我建议对整数幂使用简单的乘法,尤其是对于像平方这样的简单乘法。
  • ppow()和pow()有什么区别。
  • pow 是数学库的幂函数。 ppow 是我上面使用的pow 的实现。它不是符合标准的实现,但我假设您使用的数学库以这种方式实现pow。我用ppow 表明您的编译器的pow 可能已损坏。
【解决方案3】:

我尝试重现您的输出,但我不能。

操作系统信息:

$ 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

【讨论】:

  • 不过应该​​是评论。
  • 我的汇率不允许我发表评论。
【解决方案4】:

pow 函数使用处理器上的浮点单元时,它可能会产生异常。

当此函数执行过程中发生此类异常时,可能会返回不正确的值。

当您调用pow(i,2)i 等于5 时,您的系统上可能就是这种情况。

作为支持这个猜想的间接证据,请注意,每个5的倍数和大于5的素数的数字(在[0-49]的指定范围内)都会出现在你的素数列表中。


下面是一段代码,用于检索可能由于 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

【讨论】:

    猜你喜欢
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    相关资源
    最近更新 更多