tags:

views:

2945

answers:

16

Hello,

In my C code , i want to calculate the factorial for numbers in the range 1 to 100. For small numbers, the function works but for bigger numbers for example 100! it returns incorrect result. Any ways to handle factorial of large numbers in C ?. The compiler im using is gcc v4.3.3 . My code is as follows :

#include <stdio.h>
#include <math.h>

double print_solution(int);

int main(void)
{
        int no_of_inputs,n ;

        int ctr = 1;

        scanf("%d",&no_of_inputs); //Read no of inputs

        do
        {
                scanf("%d",&n); //Read the input

                printf("%.0f\n",print_solution(n));

                ctr++;  

        }while(ctr <= no_of_inputs);


        return 0;       
}

double print_solution(int n)
{
        if(n == 0 || n == 1)
                return 1;
        else
                return n*print_solution(n-1);


}
A: 

I guess that's because you are overflowing the int range, which is up to approx. 2 billions. You can get up to 4 billions if you use unsigned int, but beyond that you have to use the bigint library.

Stefano Borini
+22  A: 

No standard C data type will accurately handle numbers as large as 100!. Your only option if to use arbitrary precision integer arithmetic, either through a library or done by yourself.

If this is just some hobby project, I'd suggest trying it yourself. It's kind of a fun exercise. If this is work-related, use a pre-existing library.

The largest C data type you'll normally get is a 64 bit integer. 100! is in the order of 10157, which takes the better part of 500 bits to store accurately as an integer.

cletus
+1 on the fun part. We did this in college. It was illustrative at the very least. If you are doing this for professional purposes, use an existing library.
D.Shawley
+1 for "it's kind of a fun exercise"
nikie
how would you go about implementing arbitrary precision integer arithmetic in C without using a pre-existing library?
alexBrand
@alexBrand store numbers are arrays. This could be arrays of digits (characters), packing two digits into a single byte (high and low 4 bits using 0-9 for each) or one of many other schemes. Arrays can be as large as memory allows. You then need to implement the arithmetic operations in terms of those data structures.
cletus
A: 

100! = 933262154439441526816992388562667004907159682643816214685929 6389521759999322991560894146397156518286253697920827223758251185210 916864000000000000000000000000

You can't represent a number this big with an int or a long.

gshauger
+11  A: 

100 factorial is huge, to be precise it's 93326215443944152681699238856266700490715968264381621468592963895217 59999322991560894146397615651828625369792082722375825118521091686400 00000000000000000000.

Maybe you should use a bignum library like GMP. It's got nice docs, a pretty consistent interface, speed and if you're on Linux your distro probably has a package (I think mine installs it by default)

varzan
@varzan: you're missin two `0` at the end...
Christoph
You can even get the GMP library on OS X if you're willing to jump through `100!` loops.
Chris Lutz
@Chris-Lutz, nice :)
BobbyShaftoe
A: 

This is most certainly due to overflow. You need a way to represent large numbers (unsigned long long won't even cover up to 25!).

Michael Foukarakis
You're right but I would also mentioned that "unsigned long long" is not available in standard ISO C90.
BobbyShaftoe
+1  A: 

you could try going for "unsigned long long" type, but thats the maximum you can get with built in types. I'd suggest (as cletus has already mentioned) either going with a known implementation of big numbers, or writing one yourself. "its a nice exercise" x 2.

rmn
That wont allowed in ISO C90. But, I agree with the second half of your answer. :)
BobbyShaftoe
+6  A: 

If you don't want to use a bigint library, the best you can do with the stdlib is using long double and tgammal() from math.h:

long double fact(unsigned n)
{
    return tgammal(n + 1);
}

This'll get you 100! with a precision of 18 decimals on x86 (ie 80 bit long double).

An exact implementation isn't that complicated either:

#include <math.h>
#include <stdio.h>
#include <string.h>

void multd(char * s, size_t len, unsigned n)
{
    unsigned values[len];
    memset(values, 0, sizeof(unsigned) * len);
    for(size_t i = len; i--; )
    {
        unsigned x = values[i] + (s[i] - '0') * n;
        s[i] = '0' + x % 10;
        if(i) values[i - 1] += x / 10;
    }
}

void factd(char * s, size_t len, unsigned n)
{
    memset(s, '0', len - 1);
    s[len - 1] = '1';
    for(; n > 1; --n) multd(s, len, n);
}

int main(void)
{
    unsigned n = 100;
    size_t len = ceill(log10l(tgammal(n + 1)));
    char dstr[len + 1];
    dstr[len] = 0;
    factd(dstr, len, n);
    puts(dstr);
}
Christoph
That's an interesting definition of "not complicated" you're using there. To me, "not complicated" means something like `type_t fact(type_t x) { return x ? x * fact(x - 1) : 1; }`
Chris Lutz
I didn't say 'not complicated' ;) - it's just not *that complicated*: if you know how to multiply manually, the implementation is straight-forward...
Christoph
+4  A: 

Everyone is telling you the correct answer however a couple of further points.

  1. Your initial idea to use a double to get a wider range is not working because a double can not store this data precisely. It can do the calculations but with a lot of rounding. This is why bigint libraries exist.

  2. I know this is probably an example from a tutorial or examples site but doing unbounded recursion will bite you at some point. You have a recursive solution for what is essentially an iterative process. You will understand why this site is named as it is when you try running your program with larger values (Try 10000).

A simple iterative approach is as follows

  int answer, idx;

  for (answer = 1, idx = 1; idx <= no_of_inputs; idx++ ) {
    answer = answer * idx;
  }
  printf("Factorial of %3d =  %d\n", no_of_inputs, answer);
Steve Weet
@Steve Weet - You could memoize the function, which would allow it to calculate progressively larger factorials. I've found in C that there's generally very little performance gain, but that can help alleviate the recursion problem.
Chris Lutz
@Chris: I think you are thinking of recursively calculating Fibonacci numbers---a recursive factorial function should still only make N (or N+1, depending on whether you base out at 1 or 0) calls to calculate fact(N). The concern is that you're generating N or N+1 stack frames. A solution is either to write it iteratively or utilize tail recursion (gcc at least will optimize tail calls with -O2). This requires adding an explicit accumulator argument.
Derrick Turk
+1  A: 

If you want to use only the standard data types and you do not need the exact answer, then compute the logarithm of n! instead of n! itself. The logarithm of n! fits easily in a double (unless n is huge).

Jitse Niesen
A: 

Don't use the recursive algorithm I think, it is super slow, even if it is cached it will be slow. This is just something you should consider.

The reason for this is when you call fact(100) you don't actually run it 100 times, you actually run that function 5050 times. Which is bad, if it is cached then it could be 100 times, however, it is still slower to run a function call with if statements then to run a loop.

double print_solution(int n)
{
    double rval = 1;
    unsigned int i;

    for( i = 1; i <= n; i++ ) {
     rval *= i;
    }

    return rval;

}

Using arbitary-precision arithmetic you could make it go very high, however, you need to use a library to do that, or you could make your own library, but that would take a lot of time to do.

jhuni
Can you explain your 5050 calls? I can see that if you calculate each of the factorials between 1 and 100, then you'd call it that often, but for a single call to evaluate 100! - I am not yet convinced.
Jonathan Leffler
I think you are thinking of recursively calculating Fibonacci numbers---a recursive factorial function should still only make N (or N+1, depending on whether you base out at 1 or 0) calls to calculate fact(N).
Derrick Turk
+3  A: 

To compute factorials of large numbers you can go this way:

n! =  n * (n-1)!
so log(n!) = log(n) + log(n-1!)

Now you can use dynamic programming to compute log(n!) and calculate
n! as (base)^(log-value)

Neeraj
not integer, but a nice way of getting a good approximation into a double
tucuxi
A: 

Yet another (free) lib you could look into is libtommath:

http://math.libtomcrypt.com

A: 

In addition to the advice of others, I'd suggest getting familiar with the storage limits of the basic types (int, long, long long, ...) for whatever computer/platform you're actually using. ("When in doubt, print more out!")

One earlier poster referred to an 80-bit precision limit, but that's particular to an x86 CPU.

Another person cited ISO C90 several times, although C99 is the latest standard; even if many compilers haven't completely implemented C99, you will probably find that they very-very likely at least have support for long long, which should correspond to >= 64-bit precision.

Garen
A: 

this is what i made to solve a google riddle some years ago, it uses GMP library http://gmplib.org/:

#include <stdio.h>
#include "gmp.h"

void fact(mpz_t r,int n){
    unsigned int i;
    mpz_t temp;
    mpz_init(temp);
    mpz_set_ui(r,1);
    for(i=1;i<=n;i++){
        mpz_set_ui(temp,i);
        mpz_mul(r,r,temp);
    }
    mpz_clear(temp);
}
int main(void) {
    mpz_t r;
    mpz_init(r);
    fact(r,188315);
    /* fact(r,100); */
    gmp_printf("%Zd\n",r);
    mpz_clear(r);
    return(0);
}

gcc -lgmp -o fact fact.c

./fact

A: 

Why C when you got a program in assembly that can handle upto 255! !!!! See code : Assembly code to calculate upto 255!

A: 

You Can Not store a number greater than 19 digits in int. The longest data type available in C is long long, this can only store integers up to 10^19. let me give U a trick. Generally, U are told to calculate the factorial of large nos in programming contests. In such contests, your time starts at the time when u enter the no to calculate its factorial, it would be better if u calculate the factorials and store them somewhere,and print them as required, and if u start calculating the factorial then u will surely exceed time limit provided by them. IF u are thinking till where U will store the factorials then let me tell u, they also provide U a source limit, U need to calculate factorials till there.

Factorial of 18 will cross the range of long ling. So, U should use some other method like storing in Arrays. You can use character array or int array to solve your problem. Choose the one that U can implement without ant error. I used integer Array and calculated factorial of 1000.While using array U are required to store a number at an array index. This program is at my blog under Programming Section. In that program I have used an structure to store different details of the factorial like length of array, and value of factorial. Check Out this program at my blog.

My Blog's address is comphacks.wordpress.com.

Gaurav
the Us that you Use are hurting my eyes...
tucuxi