|  | #include "os.h" | 
|  | #include <mp.h> | 
|  | #include "dat.h" | 
|  |  | 
|  | mpint* | 
|  | mpfactorial(ulong n) | 
|  | { | 
|  | int i; | 
|  | ulong k; | 
|  | unsigned cnt; | 
|  | int max, mmax; | 
|  | mpdigit p, pp[2]; | 
|  | mpint *r, *s, *stk[31]; | 
|  |  | 
|  | cnt = 0; | 
|  | max = mmax = -1; | 
|  | p = 1; | 
|  | r = mpnew(0); | 
|  | for(k=2; k<=n; k++){ | 
|  | pp[0] = 0; | 
|  | pp[1] = 0; | 
|  | mpvecdigmuladd(&p, 1, (mpdigit)k, pp); | 
|  | if(pp[1] == 0)	/* !overflow */ | 
|  | p = pp[0]; | 
|  | else{ | 
|  | cnt++; | 
|  | if((cnt & 1) == 0){ | 
|  | s = stk[max]; | 
|  | mpbits(r, Dbits*(s->top+1+1)); | 
|  | memset(r->p, 0, Dbytes*(s->top+1+1)); | 
|  | mpvecmul(s->p, s->top, &p, 1, r->p); | 
|  | r->sign = 1; | 
|  | r->top = s->top+1+1;		/* XXX: norm */ | 
|  | mpassign(r, s); | 
|  | for(i=4; (cnt & (i-1)) == 0; i=i<<1){ | 
|  | mpmul(stk[max], stk[max-1], r); | 
|  | mpassign(r, stk[max-1]); | 
|  | max--; | 
|  | } | 
|  | }else{ | 
|  | max++; | 
|  | if(max > mmax){ | 
|  | mmax++; | 
|  | if(max > nelem(stk)) | 
|  | abort(); | 
|  | stk[max] = mpnew(Dbits); | 
|  | } | 
|  | stk[max]->top = 1; | 
|  | stk[max]->p[0] = p; | 
|  | } | 
|  | p = (mpdigit)k; | 
|  | } | 
|  | } | 
|  | if(max < 0){ | 
|  | mpbits(r, Dbits); | 
|  | r->top = 1; | 
|  | r->sign = 1; | 
|  | r->p[0] = p; | 
|  | }else{ | 
|  | s = stk[max--]; | 
|  | mpbits(r, Dbits*(s->top+1+1)); | 
|  | memset(r->p, 0, Dbytes*(s->top+1+1)); | 
|  | mpvecmul(s->p, s->top, &p, 1, r->p); | 
|  | r->sign = 1; | 
|  | r->top = s->top+1+1;		/* XXX: norm */ | 
|  | } | 
|  |  | 
|  | while(max >= 0) | 
|  | mpmul(r, stk[max--], r); | 
|  | for(max=mmax; max>=0; max--) | 
|  | mpfree(stk[max]); | 
|  | mpnorm(r); | 
|  | return r; | 
|  | } |