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={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 = {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";