Sindbad~EG File Manager
/* compute binomial coefficients of integer or rational arguments */
/* M. Beeson, for Mathpert */
/* Original date 1.15.99 */
/* Last modified 2.21.99 before version 1.624 */
/* 6.17.04 removed 16-bit conditional compilation */
#include <math.h>
#include <string.h> /* memcpy */
#include <assert.h>
#include <stdlib.h>
#include <malloc.h>
#define BIGNUMS_DLL
#include "export.h"
#include "heap.h" /* callocate and free2 */
#include "bignum.h"
MEXPORT_BIGNUMS bignum bigint(long m)
/* make a bignum out of m; presumes m >= 0 */
{ bignum ans;
ans.val = getspace(1);
ans.val[0] = m;
ans.ln = 1;
return ans;
}
/*____________________________________________________________*/
MEXPORT_BIGNUMS int intbinomial(long n, long k, bignum *ans)
/* compute (n choose k) and return the result in *ans. It is
assumed that k <= n and both are positive. Return 0 for success.
*/
{ bignum w,d,num,z,r;
long i;
int err;
w = bigint(1);
for(i=1; i <= k ; i++)
{ d = bigint(i);
num = bigint(n-k+i);
/* multiply by num, then divide by d */
bigmult(w,num,&z);
freespace(w.val); /* created by bigint the first time,
else by bigdivide on previous iteration */
err = bigdivide(z,d,&w,&r);
if(err)
return err;
if(r.val[0] != 0 || r.ln != 1)
assert(0); /* it must divide evenly */
freespace(z.val); /* created by bigmult above */
freespace(d.val); /* created by bigint at the top of the loop */
freespace(num.val); /* created by bigint */
}
*ans = w;
return 0;
}
/*___________________________________________________________*/
MEXPORT_BIGNUMS int ratbinomial(long p, long q, long k, bigrat *ans)
/* compute (p/q choose k), putting it in *ans and returning 0 for success.
It is assumed that k is positive and q is positive but p can be negative.
*/
{ int i;
bigrat r;
bignum bigq,w,v,w2,w3,s,trash,denom,temp,temp2,temp3;
void *saveheap;
long t;
if(k > 6)
saveheap = heapmax();
if(k == 0)
{ ans->sign = 1;
ans->n = bigint(1);
ans->d = bigint(1);
return 0;
}
if(p == 0)
{ ans->sign = 1;
ans->n = bigint(0);
ans->d = bigint(1);
return 0;
}
if(k == 1)
{ ans->n = p > 0 ? bigint(p) : bigint(-p);
ans->d = bigint(q);
ans-> sign = p > 0 ? 1 : -1;
return 0;
}
if(q == 1)
{ if(p > 0)
{ if(k > p)
{ ans->sign = 1;
ans->n = bigint(0);
ans->d = bigint(1);
return 0;
}
ans->sign = 1;
ans->d = bigint(1);
return intbinomial(p,k,&ans->n);
}
/* now p < 0 */
ans->sign = (k&0) ? -1 : 1;
ans->d = bigint(1);
return intbinomial(k-p-1,k,&ans->n);
}
if(q > 0xffff || k > 0x7fff || labs(p) > 0x7fff)
return 38;
/* Now q isn't 1 and k > 1 and p isn't 0 and
both qi and p - qi fit into a long */
r.sign = p > 0 ? 1 : -1;
r.n = p > 0 ? bigint(p): bigint(-p);
r.d = bigint(q);
bigq = bigint(q);
for(i=1;i<k;i++)
{ /* r = r*(p/q-i)/(i+1) = r *(p-qi)/(q *(i+1)) */
t = p - q*i;
if( t > 0)
bigmult(r.n,bigint(t),&w);
else
bigmult(r.n,bigint(-t),&w);
bigmult(bigq,bigint(i+1),&denom);
biggcd(w,denom,&v);
r.sign *= t > 0 ? 1 : -1;
if(v.ln == 1 && v.val[0] == 1)
{ biggcd(w,r.d,&temp);
if(temp.ln == 1 && temp.val[0] == 1)
{ bigmult(r.d,denom,&s);
r.d = s;
r.n = w;
}
else
{ bigdivide(w,temp,&temp2,&trash);
bigdivide(r.d,temp,&temp3,&trash);
bigmult(temp3,denom,&s);
r.d = s;
r.n = temp2;
}
}
else
{ bigdivide(w,v,&w2,&trash);
if(trash.ln != 1 || trash.val[0] != 0)
assert(0);
bigdivide(denom,v,&w3,&trash);
if(trash.ln != 1 || trash.val[0] != 0)
assert(0);
biggcd(w2,r.d,&temp);
if(temp.ln == 1 && temp.val[0] == 1)
{ bigmult(r.d,w3,&s);
r.n = w2;
r.d = s;
}
else
{ bigdivide(w2,temp,&temp2,&trash);
bigdivide(r.d,temp,&temp3,&trash);
bigmult(temp3,w3,&s);
r.n = temp2;
r.d = s;
}
}
}
*ans = r;
if(k > 6)
{ /* stash r somewhere temporarily and reset_heap */
digit *temp1 = (digit *) calloc(r.n.ln, sizeof(digit));
digit *temp2 = (digit *) calloc(r.d.ln, sizeof(digit));
if(!temp1 || !temp2)
return 0; /* never mind memory management */
memcpy(temp1,r.n.val,r.n.ln *sizeof(digit));
memcpy(temp2,r.d.val,r.d.ln *sizeof(digit));
reset_heap(saveheap);
r.n.val = getspace(r.n.ln);
r.d.val = getspace(r.d.ln);
memcpy(r.n.val, temp1, r.n.ln *sizeof(digit));
memcpy(r.d.val, temp2, r.d.ln *sizeof(digit));
free(temp1);
free(temp2);
}
return 0;
}
/*__________________________________________________________________*/
MEXPORT_BIGNUMS int bignum_long(bignum b, long *ans)
/* convert bignum to long if possible, returning 0 for success, 2 for failure */
/* don't make any assumptions about word size, sizeof(long), sizeof(digit),
except that sizeof(digit) is either half of sizeof(long) or equal to sizeof(long).
*/
{ if(b.ln > 2)
return 2; /* impossible conversion */
if(b.ln == 1 && sizeof(long) > sizeof(digit) )
{ *ans = (long) b.val[0];
return 0;
}
if(b.ln == 1 && !(b.val[0] >> (NN-1)))
{ *ans = (long) b.val[0];
return 0;
}
if(b.ln == 1)
return 2;
return 2;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists