📄 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/* 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 + -