📄 idigitkara.c
字号:
/* Integer Version 2.0, RD, 20.1.93 idigitkara.c *//* use DigitVecMult, RD, 24.2.93 *//* Karatsuba method for multiplication of long integers. *//* Parameters optimized for Sparc Version. */#include <iint.h>#include <idigit.h>/*#ifndef KARATSUBA_LIMIT2#define KARATSUBA_LIMIT2 15#endif*/#define KARATSUBA_LIMIT2 16/* Formulae: a == B^n a1 + a0; b == B^n b1 + b0; a b == (B^(2n) + B^n) a1 b1 + B^n (a1 - a0) (b0 - b1) + (B^n + 1) a0 b0; -----------------V | a1 b1 | ----------------- -----------------IV | a1 b1 | ----------------- -----------------III ||a1-a0||b0-b1| | ----------------- -----------------II | a0 b0 | ----------------- -----------------I | a0 b0 | ----------------- --------------------------------- | prod | --------------------------------- | | | | n3 n2 n 0*/static DigitType vecadd4carry (/*sum, a, b, c, d, carry, k*/);static int vecadd3subcarry (/*accu, a, b, c, d, carry, k*/);static DigitType vecaddDigitType (/*accu, a, d, k*/);static DigitType vecaddscarry (/*accu, a, d, k*/);void DigitVecKaratsubaM (prod, a, b, tmp, n2) DigitType *prod, *a, *b, *tmp; int n2;/* In: a[n2], b[n2]; n2 == 2^k * n0, with n0 <= KARATSUBA_LIMIT2 Out: prod[2*n2] = a[n2] * b[n2]; Local: tmp[2*n2] for intermediate results for n2>KARATSUBA_LIMIT2: karatsuba-recursion with k-1 else: standard multiplication*/{ int sign, i, n, n3; DigitType carry; int subcarry; if (n2<=KARATSUBA_LIMIT2) { /* use DigitVecMult and DigitVecMultAdd */ /* clearly n2 >= 1 */ prod[n2]=DigitVecMult(prod, a, b[0], n2); for ( i = 1; i < n2; i++) prod[i+n2] = DigitVecMultAdd(&prod[i], a, b[i], n2); return; } n=n2/2; n3=n2+n; DigitVecKaratsubaM(&prod[n2], a, b, prod, n); /* prod: | a0*b0 | | */ if (DigitVecGt(a, &a[n], n)) { sign=1; DigitVecSub(tmp, a, &a[n], n); /* a0 - a1 */ } else { sign=0; DigitVecSub(tmp, &a[n], a, n); /* a1 - a0 */ } /* tmp: | | | ||a0-a1|| */ if (DigitVecGt(&b[n], b, n)) { sign^=1; DigitVecSub(&tmp[n], &b[n], b, n); /* b1 - b0 */ } else { DigitVecSub(&tmp[n], b, &b[n], n); /* b0 - b1 */ } /* tmp: | | ||b1-b0|||a0-a1|| */ DigitVecKaratsubaM(&tmp[n2], tmp, &tmp[n], prod, n); /* tmp: ||b1-b0|*|a0-a1|||b1-b0|||a0-a1|| */ DigitVecKaratsubaM(tmp, &a[n], &b[n], prod, n); /* tmp: ||b1-b0|*|a0-a1|| a1*b1 | */ /* --------------------------------- prod | a0 b0 | | --------------------------------- --------------------------------- tmp ||a1-a0||b0-b1| | a1 b1 | --------------------------------- */ if (sign==0) { /* Einfach addieren */ for (i=0; i<n; i++) prod[i]=prod[n2+i]; /* I */ /* I + II + III + IV */ carry=vecadd4carry(&prod[n], &prod[n3], &prod[n2], &tmp[n2], tmp, 0, n); /* carry + II + III + IV + V */ carry=vecadd4carry(&prod[n2], &prod[n3], &tmp[n3], &tmp[n], tmp, carry, n); /* carry + V */ vecaddDigitType(&prod[n3], &tmp[n], carry, n); } else { /* III subtrahieren */ for (i=0; i<n; i++) prod[i]=prod[n2+i]; /* I */ /* I + II + IV - III */ subcarry=vecadd3subcarry(&prod[n], &prod[n3], &prod[n2], tmp, &tmp[n2], 0, n); /* carry + II + IV + V - III */ subcarry=vecadd3subcarry(&prod[n2], &prod[n3], &tmp[n], tmp, &tmp[n3], subcarry, n); /* subcarry + V */ vecaddscarry (&prod[n3], &tmp[n], subcarry, n); }}static DigitType vecadd4carry (accu, a, b, c, d, carry, k) DigitType *accu, *a, *b, *c, *d, carry; int k; /* accu[k]=a[k]+b[k]+c[k]+d[k]+carry; return carry; */{ DigitType aa, bb, cc, dd, sum; for ( ; k>0; k--) { aa=*a++; bb=*b++; cc=*c++; dd=*d++; sum = aa+carry; carry = (sum < aa); sum += bb; carry += (sum < bb); sum += cc; carry += (sum < cc); sum += dd; carry += (sum < dd); *accu++= sum; } return carry;}static int vecadd3subcarry (accu, a, b, c, d, carry, k) DigitType *accu, *a, *b, *c, *d; int carry, k; /* carry >= -1 */ /* accu[k]=a[k]+b[k]+c[k]-d[k]+carry; return carry; */{ DigitType aa, bb, cc, dd, sum, tmp, subc; if (carry < 0) { subc = 1; carry = 0; } else { subc=0; } for ( ; k>0; k--) { aa=*a++; bb=*b++; cc=*c++; dd=*d++; sum = aa+carry; carry = (sum < aa); sum += bb; carry += (sum < bb); sum += cc; carry += (sum < cc); tmp = sum - subc; subc = (tmp > sum); sum = tmp - dd; subc += (sum > tmp); *accu++= sum; } return carry-subc;}static DigitType vecaddDigitType (accu, a, d, k) DigitType *accu, *a, d; int k; /* accu[k]=a[k]+d; return carry; */{ DigitType sum, carry=d; for ( ; k>0; k-- ) { sum = *a++ + carry; carry = (sum < carry); *accu++ = sum; } return carry;}/* ACHTUNG: k==0 ==> carry==d */static DigitType vecaddscarry (accu, a, scarry, k) DigitType *accu, *a; int scarry, k; /* 2^BitsPerDigit > scarry >=-1 */ /* accu[k]=a[k]+scarry; return carry; */{ DigitType sum, carry, tmp; if (scarry >= 0) { carry = scarry; for ( ; k>0; k-- ) { sum = *a++ + carry; carry = (sum < carry); *accu++ = sum; } return carry; } else { carry = 1; for ( ; k>0; k-- ) { tmp = *a++; sum = tmp - carry; carry = (sum > tmp); *accu++ = sum; } return -carry; }}/* ACHTUNG: k==0 ==> carry==scarry */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -