简体   繁体   中英

Why is this program giving me a SIGFPE?

I am getting SIGFPE Error in the below program and cannot think of a way to remove it.

#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;
}

I am trying to calculate a series which needs factorial but this is giving me SIGFPE error. I use 35 as input.

link to the question: screen shot

solution

35! exceeds the capacity of an unsigned int on your platform by far.

What happens then is that fact(35) returns 0, which results in a division by 0 hence the SIGFPE ( f loating p oint e xception).

Consider using the unsigned long long type, but this won't help for 35 either, because 35! is really huge.

In addition to Jabberwocky answer.

Overflow is not the only reason, yoh have overflow of a 'round' number...

fact(34) returns the amazing result of 0.

If it was a uint64 return value and arg

unsigned long long fact(unsigned long long n)

and you print the result with

printf("%llx",x);

you'll get the result: 445da75b00000000

Cast it to int and you'll get a perfect 0.

It is logical since you have multiply a lot of even numbers and some of the are even power of 2.

You just need 32 2s multiplies to reach this result:

  • 2,6,10,14,18,22,26,30,34 each give you one 2 so you have 9 2s
  • 4,12,20,28 each give you 4, which is 2*2, so it gives you 8 2s, so you already have 17 2s
  • 8,24 give you 8 which is 2*2*2, so you have more 6 2s, and total is 23 2s
  • 16 give you more 4 2s, so you have 27 2s
  • 32 give you more 5 2s, so you have exactly 32 2s.

In your program, you calculate the binomial coefficient C(n, k) for each possible number of two-task days. The formula is simple:

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

but using this formula directly has several problems: The intermediate results, namely the factorials, overflow quickly. Unsigned 32-bit integers can hold factoials up to 12!, unsigned 64-bit integers can hold up to 20!, but after that you will need bignum libraries. The problem statement says that the number of tasks, N, is at most 80. I believe this limit was chosen so that you can do all calculations with uint64_t from <stdint.h> .

There are other problems; Raymond Chen outlines them more elegantly than I can. He also proposes a simple way to calculate binomial coefficients, which you can adopt:

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;
}

Oh, and you don't need to distinguish between odd and even N's.

And there's something strange about the challenge: N is the only parameter for each testcase and it can range from 1 to 80, but there can be up to 10,000 test cases. If there are more than 80 cases, N will repeat. Maybe they want you to memoize the results in an array, so that the first time you calculate bthe result, store it and the next time you have to calculate for the same N again, just use the precalculated value. This saves time, and "Time limit exceeded" is a very frequent error in online contests.

You could also try to calculate the first couple of results, say for N from 1 to 10, and print them. Notice a pattern? See, you didn't need the binomial coefficients at all. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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