繁体   English   中英

为什么该程序给我SIGFPE?

[英]Why is this program giving me a SIGFPE?

我在下面的程序中收到SIGFPE错误,无法想到将其删除的方法。

#include <stdio.h>

unsigned int fact(unsigned long int n)
{
    if (n <= 0)
        return 1;
    return n*fact(n-1);
}


int main(){
    int t,r,x,y,z,sum=0,n;

    scanf("%d",&t);

    for(int l=0; l<t; l++){

        scanf("%d",&n );

        if(n%2==0){
            for(int j=n,i=0,k=n; k>=0&&j>0;i++, j++,k-=2){
                x=fact(n-i);
                y=fact(k);
                z=fact(n-k-i);
                sum=sum+  (x)/(y*z);
            }
            printf("%d\n",sum );
        }

        if(n%2!=0){
            for(int j=n,i=0,k=n; k>=1&&j>0;i++, j++,k-=2){
                x=fact(n-i);
                y=fact(k);
                z=fact(n-k-i);
                sum=sum+  (x)/(y*z);

            }
            printf("%d\n",sum);
        }
        sum=0;

    }
    return 0;
}

我正在尝试计算需要阶乘的级数,但这给了我SIGFPE错误。 我使用35作为输入。

链接到问题: 屏幕截图

35! 远远超过了平台上unsigned int的容量。

会发生什么然后是fact(35)返回0,其结果在被零除因此SIGFPE(F loating p ointëxception)。

考虑使用unsigned long long类型,但这对35也不起作用,因为35! 真的很大

除了Jabberwocky的答案。

溢出不是唯一的原因,哦,有一个“整数”溢出...

fact(34)返回惊人的结果0。

如果是uint64返回值, uint64返回arg

unsigned long long fact(unsigned long long n)

然后用

printf("%llx",x);

您将得到结果:445da75b00000000

将其强制转换为int即可得到完美的0。

这是合乎逻辑的,因为您已将许多偶数相乘,并且有些数字是2的偶数幂。

您只需要乘以32 2s即可达到以下结果:

  • 2,6,10,14,18,22,26,30,34每个给您一个2所以您有9 2s
  • 4,12,20,28分别给您4,即2 * 2,所以它给您8 2s,所以您已经有17 2s
  • 8,24给您8,即2 * 2 * 2,所以您还有6 2s,总共是23 2s
  • 16给你更多4 2s,所以你有27 2s
  • 32给您5 2s,所以您恰好有32 2s。

在您的程序中,您将为每个可能的两个任务天数计算二项式系数C(n,k)。 公式很简单:

C(n, k) = n! / (k! * (n - k)!)

但是直接使用此公式有几个问题:中间结果,即阶乘,迅速溢出。 无符号的32位整数最多可容纳12!个事实,无符号的64位整数最多可容纳20!个,但是此后,您将需要bignum库。 问题陈述指出,任务数N最多为80。我相信选择了此限制,以便您可以使用<stdint.h> uint64_t进行所有计算。

还有其他问题; 雷蒙·陈(Raymond Chen)尽我所能勾勒出它们的优美轮廓。 他还提出了一种计算二项式系数的简单方法,您可以采用:

uint64_t binom(uint64_t n, uint64_t k)
{
    uint64_t c = 1u;
    uint64_t i;

    for (i = 0; i < k; i++) {
        c *= n - i;
        c /= i + 1;
    }

    return c;
}

哦,您不需要区分N的奇数和偶数。

挑战有一个奇怪的地方:N是每个测试用例的唯一参数,范围可以从1到80,但是最多可以有10,000个测试用例。 如果超过80个,N将重复。 也许他们希望您将结果记忆在一个数组中,以便第一次计算该结果时将其存储起来,而下次您必须再次针对相同的N计算时,只需使用预先计算的值即可。 这样可以节省时间,并且“超过时间限制”是在线竞赛中非常常见的错误。

您也可以尝试计算前几个结果,例如N的范围是1到10,并打印出来。 注意到模式吗? 看,您根本不需要二项式系数。 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM