1*7dd7cddfSDavid du Colombier #include "os.h" 2*7dd7cddfSDavid du Colombier #include <mp.h> 3*7dd7cddfSDavid du Colombier #include "dat.h" 4*7dd7cddfSDavid du Colombier 5*7dd7cddfSDavid du Colombier // 6*7dd7cddfSDavid du Colombier // from knuth's 1969 seminumberical algorithms, pp 233-235 and pp 258-260 7*7dd7cddfSDavid du Colombier // 8*7dd7cddfSDavid du Colombier // mpvecmul is an assembly language routine that performs the inner 9*7dd7cddfSDavid du Colombier // loop. 10*7dd7cddfSDavid du Colombier // 11*7dd7cddfSDavid du Colombier // the karatsuba trade off is set empiricly by measuring the algs on 12*7dd7cddfSDavid du Colombier // a 400 MHz Pentium II. 13*7dd7cddfSDavid du Colombier // 14*7dd7cddfSDavid du Colombier 15*7dd7cddfSDavid du Colombier // karatsuba like (see knuth pg 258) 16*7dd7cddfSDavid du Colombier // prereq: p is already zeroed 17*7dd7cddfSDavid du Colombier static void 18*7dd7cddfSDavid du Colombier mpkaratsuba(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p) 19*7dd7cddfSDavid du Colombier { 20*7dd7cddfSDavid du Colombier mpdigit *t, *u0, *u1, *v0, *v1, *u0v0, *u1v1, *res, *diffprod; 21*7dd7cddfSDavid du Colombier int u0len, u1len, v0len, v1len, reslen; 22*7dd7cddfSDavid du Colombier int sign, n; 23*7dd7cddfSDavid du Colombier 24*7dd7cddfSDavid du Colombier // divide each piece in half 25*7dd7cddfSDavid du Colombier n = alen/2; 26*7dd7cddfSDavid du Colombier if(alen&1) 27*7dd7cddfSDavid du Colombier n++; 28*7dd7cddfSDavid du Colombier u0len = n; 29*7dd7cddfSDavid du Colombier u1len = alen-n; 30*7dd7cddfSDavid du Colombier if(blen > n){ 31*7dd7cddfSDavid du Colombier v0len = n; 32*7dd7cddfSDavid du Colombier v1len = blen-n; 33*7dd7cddfSDavid du Colombier } else { 34*7dd7cddfSDavid du Colombier v0len = blen; 35*7dd7cddfSDavid du Colombier v1len = 0; 36*7dd7cddfSDavid du Colombier } 37*7dd7cddfSDavid du Colombier u0 = a; 38*7dd7cddfSDavid du Colombier u1 = a + u0len; 39*7dd7cddfSDavid du Colombier v0 = b; 40*7dd7cddfSDavid du Colombier v1 = b + v0len; 41*7dd7cddfSDavid du Colombier 42*7dd7cddfSDavid du Colombier // room for the partial products 43*7dd7cddfSDavid du Colombier t = mallocz(Dbytes*5*(2*n+1), 1); 44*7dd7cddfSDavid du Colombier if(t == nil) 45*7dd7cddfSDavid du Colombier sysfatal("mpkaratsuba"); 46*7dd7cddfSDavid du Colombier u0v0 = t; 47*7dd7cddfSDavid du Colombier u1v1 = t + (2*n+1); 48*7dd7cddfSDavid du Colombier diffprod = t + 2*(2*n+1); 49*7dd7cddfSDavid du Colombier res = t + 3*(2*n+1); 50*7dd7cddfSDavid du Colombier reslen = 4*n+1; 51*7dd7cddfSDavid du Colombier 52*7dd7cddfSDavid du Colombier // t[0] = (u1-u0) 53*7dd7cddfSDavid du Colombier sign = 1; 54*7dd7cddfSDavid du Colombier if(mpveccmp(u1, u1len, u0, u0len) < 0){ 55*7dd7cddfSDavid du Colombier sign = -1; 56*7dd7cddfSDavid du Colombier mpvecsub(u0, u0len, u1, u1len, u0v0); 57*7dd7cddfSDavid du Colombier } else 58*7dd7cddfSDavid du Colombier mpvecsub(u1, u1len, u0, u1len, u0v0); 59*7dd7cddfSDavid du Colombier 60*7dd7cddfSDavid du Colombier // t[1] = (v0-v1) 61*7dd7cddfSDavid du Colombier if(mpveccmp(v0, v0len, v1, v1len) < 0){ 62*7dd7cddfSDavid du Colombier sign *= -1; 63*7dd7cddfSDavid du Colombier mpvecsub(v1, v1len, v0, v1len, u1v1); 64*7dd7cddfSDavid du Colombier } else 65*7dd7cddfSDavid du Colombier mpvecsub(v0, v0len, v1, v1len, u1v1); 66*7dd7cddfSDavid du Colombier 67*7dd7cddfSDavid du Colombier // t[4:5] = (u1-u0)*(v0-v1) 68*7dd7cddfSDavid du Colombier mpvecmul(u0v0, u0len, u1v1, v0len, diffprod); 69*7dd7cddfSDavid du Colombier 70*7dd7cddfSDavid du Colombier // t[0:1] = u1*v1 71*7dd7cddfSDavid du Colombier memset(t, 0, 2*(2*n+1)*Dbytes); 72*7dd7cddfSDavid du Colombier if(v1len > 0) 73*7dd7cddfSDavid du Colombier mpvecmul(u1, u1len, v1, v1len, u1v1); 74*7dd7cddfSDavid du Colombier 75*7dd7cddfSDavid du Colombier // t[2:3] = u0v0 76*7dd7cddfSDavid du Colombier mpvecmul(u0, u0len, v0, v0len, u0v0); 77*7dd7cddfSDavid du Colombier 78*7dd7cddfSDavid du Colombier // res = u0*v0<<n + u0*v0 79*7dd7cddfSDavid du Colombier mpvecadd(res, reslen, u0v0, u0len+v0len, res); 80*7dd7cddfSDavid du Colombier mpvecadd(res+n, reslen-n, u0v0, u0len+v0len, res+n); 81*7dd7cddfSDavid du Colombier 82*7dd7cddfSDavid du Colombier // res += u1*v1<<n + u1*v1<<2*n 83*7dd7cddfSDavid du Colombier if(v1len > 0){ 84*7dd7cddfSDavid du Colombier mpvecadd(res+n, reslen-n, u1v1, u1len+v1len, res+n); 85*7dd7cddfSDavid du Colombier mpvecadd(res+2*n, reslen-2*n, u1v1, u1len+v1len, res+2*n); 86*7dd7cddfSDavid du Colombier } 87*7dd7cddfSDavid du Colombier 88*7dd7cddfSDavid du Colombier // res += (u1-u0)*(v0-v1)<<n 89*7dd7cddfSDavid du Colombier if(sign < 0) 90*7dd7cddfSDavid du Colombier mpvecsub(res+n, reslen-n, diffprod, u0len+v0len, res+n); 91*7dd7cddfSDavid du Colombier else 92*7dd7cddfSDavid du Colombier mpvecadd(res+n, reslen-n, diffprod, u0len+v0len, res+n); 93*7dd7cddfSDavid du Colombier memmove(p, res, (alen+blen)*Dbytes); 94*7dd7cddfSDavid du Colombier 95*7dd7cddfSDavid du Colombier free(t); 96*7dd7cddfSDavid du Colombier } 97*7dd7cddfSDavid du Colombier 98*7dd7cddfSDavid du Colombier #define KARATSUBAMIN 32 99*7dd7cddfSDavid du Colombier 100*7dd7cddfSDavid du Colombier void 101*7dd7cddfSDavid du Colombier mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p) 102*7dd7cddfSDavid du Colombier { 103*7dd7cddfSDavid du Colombier int i; 104*7dd7cddfSDavid du Colombier mpdigit d; 105*7dd7cddfSDavid du Colombier mpdigit *t; 106*7dd7cddfSDavid du Colombier 107*7dd7cddfSDavid du Colombier // both mpvecdigmuladd and karatsuba are fastest when a is the longer vector 108*7dd7cddfSDavid du Colombier if(alen < blen){ 109*7dd7cddfSDavid du Colombier i = alen; 110*7dd7cddfSDavid du Colombier alen = blen; 111*7dd7cddfSDavid du Colombier blen = i; 112*7dd7cddfSDavid du Colombier t = a; 113*7dd7cddfSDavid du Colombier a = b; 114*7dd7cddfSDavid du Colombier b = t; 115*7dd7cddfSDavid du Colombier } 116*7dd7cddfSDavid du Colombier if(blen == 0){ 117*7dd7cddfSDavid du Colombier memset(p, 0, Dbytes*(alen+blen)); 118*7dd7cddfSDavid du Colombier return; 119*7dd7cddfSDavid du Colombier } 120*7dd7cddfSDavid du Colombier 121*7dd7cddfSDavid du Colombier if(alen >= KARATSUBAMIN && blen > 1){ 122*7dd7cddfSDavid du Colombier // O(n^1.585) 123*7dd7cddfSDavid du Colombier mpkaratsuba(a, alen, b, blen, p); 124*7dd7cddfSDavid du Colombier } else { 125*7dd7cddfSDavid du Colombier // O(n^2) 126*7dd7cddfSDavid du Colombier for(i = 0; i < blen; i++){ 127*7dd7cddfSDavid du Colombier d = b[i]; 128*7dd7cddfSDavid du Colombier if(d != 0) 129*7dd7cddfSDavid du Colombier mpvecdigmuladd(a, alen, d, &p[i]); 130*7dd7cddfSDavid du Colombier } 131*7dd7cddfSDavid du Colombier } 132*7dd7cddfSDavid du Colombier } 133*7dd7cddfSDavid du Colombier 134*7dd7cddfSDavid du Colombier void 135*7dd7cddfSDavid du Colombier mpmul(mpint *b1, mpint *b2, mpint *prod) 136*7dd7cddfSDavid du Colombier { 137*7dd7cddfSDavid du Colombier mpint *oprod; 138*7dd7cddfSDavid du Colombier 139*7dd7cddfSDavid du Colombier oprod = nil; 140*7dd7cddfSDavid du Colombier if(prod == b1 || prod == b2){ 141*7dd7cddfSDavid du Colombier oprod = prod; 142*7dd7cddfSDavid du Colombier prod = mpnew(0); 143*7dd7cddfSDavid du Colombier } 144*7dd7cddfSDavid du Colombier 145*7dd7cddfSDavid du Colombier prod->top = 0; 146*7dd7cddfSDavid du Colombier mpbits(prod, (b1->top+b2->top+1)*Dbits); 147*7dd7cddfSDavid du Colombier mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p); 148*7dd7cddfSDavid du Colombier prod->sign = b1->sign*b2->sign; 149*7dd7cddfSDavid du Colombier mpnorm(prod); 150*7dd7cddfSDavid du Colombier 151*7dd7cddfSDavid du Colombier if(oprod != nil){ 152*7dd7cddfSDavid du Colombier mpassign(prod, oprod); 153*7dd7cddfSDavid du Colombier mpfree(prod); 154*7dd7cddfSDavid du Colombier } 155*7dd7cddfSDavid du Colombier } 156