http://www.perlmonks.org?node_id=442521

monkfan has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
Here is the code that tries to compute factorial based on Numerical Recipes using Inline::C.

My question is, how can I improve my code below so that it can handle large number? Does Inline::C support malloc for typdef?

I've tried "Math::Pari qw(:int)" but of no avail. So I thought malloc should be the better way to go.
#!/usr/bin/perl -w use strict; use Inline qw(C); use Data::Dumper; my $n = factrl(1000); print "$n\n"; __END__ __C__ /* Here I attempt to increase the size of variable with malloc such that it can handle BIG number But is there anything wrong with it? */ typedef (malloc(2*sizeof(long double))) Big_Double; Big_Double factrl; /* Code below is to compute factorial */ double factrl(int n) { double gammln(double xx); void nerror(char error_text[]); static int ntop=4; static double a[33]={1.0,1.0,2.0,6.0,24.0}; int j; if (n<0) nerror("Negative factorial in routine factrl"); if (n>32) return exp(gammln(n+1.0)); while (ntop<n){ j = ntop++; a[ntop]=a[j]*ntop; } return a[n]; } double gammln(double xx) { double x,y, tmp,ser; static double cof[6] = {76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.12086509738661e-2, -0.5395239384953e-5}; int j; y = x = xx; tmp= x+5.5; tmp -= (x+0.5)*log(tmp); ser=1.000000000190015; for (j=0;j<=5;j++) ser += cof[j]/++y; return -tmp+log(2.5066282746310005*ser/x); }
Regards,
Edward

Update: I've also tried "use Math::GMP qw(:constant);" also can't handle big N.

Replies are listed 'Best First'.
Re: Malloc with Inline::C
by ambs (Pilgrim) on Mar 26, 2005 at 17:53 UTC
    I would suggest two ways:
    • try to use GMP and Inline::C. GMP is a multi precision library for integers and reals. (GNU Multi Precision library)
    • try to use large numbers modules in Perl (but you will loose speed)
    Also, it is possible that there is a GMP module for Perl.

    Alberto Simões

Re: Malloc with Inline::C
by tall_man (Parson) on Mar 27, 2005 at 06:07 UTC
    typedef (malloc(2*sizeof(long double))) Big_Double; Big_Double factrl;

    Malloc is a function to allocate memory dynamically. It has no business in a typedef. Even if you did allocate a big variable, that would not automatically give you extended precision arithmetic.

    From your other postings, it looks like you want to calculate binomial coefficients. The binomial coefficients may not overflow even if the factorials do. Say you wanted 1000 choose 5 = 1000!/(1000-5)!(5!). Your gammln gives you logs, so you could compute:

    exp(gammln(1001.0) - gammln(996.0) - gammln(6.0));

    But if you really want to print the values of huge factorials for some reason, here's another trick you could use: convert your gammln to a decimal log, and truncate to get the exponent, like this:

    my $n = gammln(1000 + 1.0)/log(10.0); my $exp = int($n); my $mantissa = 10.0 ** ($n - $exp); printf "${mantissa}e$exp\n";
Re: Malloc with Inline::C
by polettix (Vicar) on Mar 26, 2005 at 18:30 UTC
    I've not tried, but the compiler should choke at it. It seems that you don't need it, because the factorial function caches values up to 33, while for larger numbers uses the log-gamma to approximate the factorial you're looking for. Given that it's an approximation, why don't you re-implement gammln in straight Perl and try to get rid of the C function in a first step?

    Anyway, if you want some BigDouble you should look for some ad-hoc lib (like GMP cited above) - if it were as simple as you're trying, those libs probably wouldn't exist :) Moreover, are you really convinced you need to compute such big factorials? (This is becoming OT, so if you want write about it in some math forum or, if you want my opinion, write me to flavio (at) polettix (dot) it).

    Flavio

    Don't fool yourself.
A reply falls below the community's threshold of quality. You may see it by logging in.