📄 imul.c
字号:
/* Integer Version 2.0, RD, 21.1.93 imul.c */#include <iint.h>#include <idigit.h>#include <imem.h>#ifdef DO_NOT_USE_KARATSUBAvoid IasImuI(accu, a, b) pInteger accu; const Integer *a, *b;/* accu=a*b; */{ register int i, al, bl, neededlength; register DigitType *paccu, *pa, *pb; if (accu == a) { ImuasI(accu, b); return; } if (accu == b) { ImuasI(accu, a); return; } al = a->length; bl = b->length; if (!al || !bl) { Iasint(accu, 0); return; } neededlength = al + bl; if (neededlength > accu->maxlength) { delDigitVec(accu->vec, accu->maxlength); accu->maxlength = neededlength; paccu = newDigitVec(&accu->maxlength); accu->vec = paccu; } else paccu = accu->vec; pa = a->vec; pb = b->vec; if (al > bl) { for (i = 0; i < al; i++) paccu[i] = 0; for (i = 0; i < bl; i++) paccu[i + al] = DigitVecMultAdd(paccu + i, pa, pb[i], al); } else { for (i = 0; i < bl; i++) paccu[i] = 0; for (i = 0; i < al; i++) paccu[i + bl] = DigitVecMultAdd(paccu + i, pb, pa[i], bl); } if (paccu[neededlength - 1]) accu->length = neededlength; else accu->length = neededlength - 1; accu->sign = a->sign ^ b->sign;} /* IasImuI */void ImuasI(a, b) Integer *a; const Integer *b;/* a*=b; */{ int maxl; register DigitType *paccu, *pa, *pb; register int i, al, bl; al = a->length; bl = b->length; if (!al || !bl) { Iasint(a, 0); return; } maxl = al + bl; paccu = newDigitVec(&maxl); pa = a->vec; pb = b->vec; if (al > bl) { for (i = 0; i < al; i++) paccu[i] = 0; for (i = 0; i < bl; i++) paccu[i + al] = DigitVecMultAdd(paccu + i, pa, pb[i], al); } else { for (i = 0; i < bl; i++) paccu[i] = 0; for (i = 0; i < al; i++) paccu[i + bl] = DigitVecMultAdd(paccu + i, pb, pa[i], bl); } al += bl; if (paccu[al - 1]) a->length = al; else a->length = al - 1; a->sign ^= b->sign; delDigitVec(a->vec, a->maxlength); a->vec = paccu; a->maxlength = maxl;} /* ImuasI */#else/* use karatsuba *//* Prerequisite: enough space in the vectors to increase the length appropriately, given with the built-in memory management.*/#ifndef KARATSUBA_LIMIT1#define KARATSUBA_LIMIT1 15#endif#ifndef KARATSUBA_LIMIT2#define KARATSUBA_LIMIT2 KARATSUBA_LIMIT1#endifstatic void do_karatsuba( /* paccu, pa, pb, al, bl */ );void IasImuI(accu, a, b) Integer *accu; const Integer *a, *b;/* accu=a*b; *//* Karatsuba, verwendet do_karatsuba */{ register int i, al, bl, neededlength; register DigitType *paccu, *pa, *pb; if (accu == a) { ImuasI(accu, b); return; } if (accu == b) { ImuasI(accu, a); return; } al = a->length; bl = b->length; if (!al || !bl) { Iasint(accu, 0); return; } neededlength = al + bl; if (neededlength > accu->maxlength) { delDigitVec(accu->vec, accu->maxlength); accu->maxlength = neededlength; paccu = newDigitVec(&accu->maxlength); accu->vec = paccu; } else paccu = accu->vec; if (al > bl) { if (bl <= KARATSUBA_LIMIT1) { /* Standardmultiplikation */ pa = a->vec; pb = b->vec; for (i = 0; i < al; i++) paccu[i] = 0; for (i = 0; i < bl; i++) paccu[i + al] = DigitVecMultAdd(paccu + i, pa, pb[i], al); } else do_karatsuba(paccu, a->vec, b->vec, al, bl); } else { if (al <= KARATSUBA_LIMIT1) { /* Standardmultiplikation */ pa = a->vec; pb = b->vec; for (i = 0; i < bl; i++) paccu[i] = 0; for (i = 0; i < al; i++) paccu[i + bl] = DigitVecMultAdd(paccu + i, pb, pa[i], bl); } else do_karatsuba(paccu, b->vec, a->vec, bl, al); } if (paccu[neededlength - 1]) accu->length = neededlength; else accu->length = neededlength - 1; accu->sign = a->sign ^ b->sign;} /* IasImuI, karatsuba */void ImuasI(a, b) pInteger a; const Integer *b;/* a*=b; *//* Karatsuba, verwendet do_karatsuba */{ int maxl; register DigitType *paccu, *pa, *pb; register int i, al, bl; al = a->length; bl = b->length; if (!al || !bl) { Iasint(a, 0); return; } maxl = al + bl; paccu = newDigitVec(&maxl); if (al > bl) { if (bl <= KARATSUBA_LIMIT1) { /* Standardmultiplikation */ pa = a->vec; pb = b->vec; for (i = 0; i < al; i++) paccu[i] = 0; for (i = 0; i < bl; i++) paccu[i + al] = DigitVecMultAdd(paccu + i, pa, pb[i], al); } else do_karatsuba(paccu, a->vec, b->vec, al, bl); } else { if (al <= KARATSUBA_LIMIT1) { /* Standardmultiplikation */ pa = a->vec; pb = b->vec; for (i = 0; i < bl; i++) paccu[i] = 0; for (i = 0; i < al; i++) paccu[i + bl] = DigitVecMultAdd(paccu + i, pb, pa[i], bl); } else do_karatsuba(paccu, b->vec, a->vec, bl, al); } al += bl; if (paccu[al - 1]) a->length = al; else a->length = al - 1; a->sign ^= b->sign; delDigitVec(a->vec, a->maxlength); a->vec = paccu; a->maxlength = maxl;} /* ImuasI, karatsuba */static void do_karatsuba(paccu, pa, pb, al, bl) DigitType *paccu, *pa, *pb; int al, bl; /* now pb is the shorter number */{ DigitType *tprod, *tmp, *res; int i, tmpl, k, q, r, n, n0, resl; /* calculate k minimal with bl <= 2^k*n0 and n0<=KARATSUBA_LIMIT2, n=2^k*n0 */ n0 = bl; k = 0; while (n0 > KARATSUBA_LIMIT2) { n0 = (n0 + 1) / 2; k++; } n = n0 << k; /* fill a, b with zeroes, maybe al <= n */ for (i = bl; i < n; i++) pb[i] = 0; for (i = al; i < n; i++) pa[i] = 0; /* split a */ q = al / n; r = al % n; if (q == 0) { /* case al < n */ q = 1; r = 0; } /* Now get temporaries for result of DigitVecKaratsubaM and tmp */ tmpl = 2 * n; tmp = newDigitVec(&tmpl); tprod = newDigitVec(&tmpl); /* Get temporary for result. */ /* TP: old: resl = al + n; */ resl = al + n + 1; res = newDigitVec(&resl); /* calculate via DigitVecKaratsubaM a_i * b, 0<= i <q */ DigitVecKaratsubaM(res, pa, pb, tmp, n); for (i = 1; i < q; i++) { DigitVecKaratsubaM(tprod, &pa[i * n], pb, tmp, n); DigitVecCadd(&res[i * n], &res[i * n], tprod, n, 2 * n); } /* calculate a_q * b */ for (i = q * n; i < al; i++) res[i + bl] = DigitVecMultAdd(&res[i], pb, pa[i], bl); for (i = 0; i < al + bl; i++) paccu[i] = res[i]; delDigitVec(tmp, tmpl); delDigitVec(tprod, tmpl); delDigitVec(res, resl);} /* do_karatsuba */#endif/* DO_NOT_USE_KARATSUBA */#ifdef __GNUC__void IasImuD(Integer * accu, const Integer * b, DigitType c)#elsevoid IasImuD(accu, b, c) register Integer *accu; const Integer *b; DigitType c;#endif{ register int nl; register DigitType carry; if (accu == b) { ImuasD(accu, c); return; } if (!c) { Iasint(accu, 0); return; } nl = b->length + 1; if (nl > accu->maxlength) { delDigitVec(accu->vec, accu->maxlength); accu->maxlength = nl; accu->vec = newDigitVec(&accu->maxlength); } carry = DigitVecMult(accu->vec, b->vec, c, b->length); accu->vec[nl - 1] = carry; if (carry) accu->length = nl; else accu->length = nl - 1; accu->sign = b->sign;} /* IasImuD */#ifdef __GNUC__void ImuasD(Integer * accu, DigitType b)#elsevoid ImuasD(accu, b) register pInteger accu; DigitType b;#endif{ register DigitType carry, *paccu; register int nl; BOOLEAN neednew; int maxl; if (!b) { Iasint(accu, 0); return; } nl = accu->length + 1; if (nl > accu->maxlength) { neednew = TRUE; maxl = nl; paccu = newDigitVec(&maxl); } else { paccu = accu->vec; neednew = FALSE; } carry = DigitVecMult(paccu, accu->vec, b, accu->length); paccu[nl - 1] = carry; if (carry) accu->length = nl; if (neednew) { delDigitVec(accu->vec, accu->maxlength); accu->vec = paccu; accu->maxlength = maxl; }} /* ImuasD *//****************************************************/void IasIsrD(a, b, count) register pInteger a; register const Integer *b; DigitType count;/* Shift nach rechts */{ register DigitType accu, help, *pa, *pb; register int i; int pts, bts, bleft, nl; if (a == b) { IsrasD(a, count); return; } pts = count / BitsPerDigit; if (pts >= b->length) { Ias0(a); return; } bts = count % BitsPerDigit; bleft = BitsPerDigit - bts; nl = b->length - pts; if (nl > a->maxlength) { delDigitVec(a->vec, a->maxlength); a->maxlength = nl; a->vec = newDigitVec(&a->maxlength); } pa = a->vec; pb = b->vec; if (!bts) { for (i = pts; i < b->length; i++) pa[i - pts] = pb[i]; a->length = nl; a->sign = b->sign; return; } accu = pb[pts]; accu >>= bts; for (i = pts + 1; i < b->length; i++) { help = pb[i]; accu |= (help << bleft); pa[i - pts - 1] = accu; accu = help >> bts; } pa[nl - 1] = accu; if (accu) a->length = nl; else a->length = nl - 1; if (a->length) a->sign = b->sign; else a->sign = PLUS;} /* IasIsrD */void IsrasD(a, count) register pInteger a; DigitType count;/* Shift nach rechts */{ register DigitType accu, help, *p; register int i; int pts, bts, bleft, l; pts = count / BitsPerDigit; if (pts >= a->length) { Ias0(a); return; } bts = count % BitsPerDigit; bleft = BitsPerDigit - bts; p = a->vec; if (!bts) { for (i = pts; i < a->length; i++) p[i - pts] = p[i]; a->length = a->length - pts; return; } accu = p[pts]; accu >>= bts; for (i = pts + 1; i < a->length; i++) { help = p[i]; accu |= (help << bleft); p[i - pts - 1] = accu; accu = help >> bts; } l = a->length - pts; if (accu) { p[l - 1] = accu; a->length = l; } else a->length = l - 1; if (!a->length) a->sign = PLUS;} /* IsrasD */void IasIslD(a, b, count) register pInteger a; register const Integer *b; DigitType count;/* Shift nach links */{ register DigitType accu, help, *pa, *pb; register int i; int pts, bts, bleft, nl; if (!b->length) { Iasint(a, 0); return; } if (a == b) { IslasD(a, count); return; } pts = count / BitsPerDigit; bts = count % BitsPerDigit; bleft = BitsPerDigit - bts; nl = b->length + pts + 1; if (nl > a->maxlength) { delDigitVec(a->vec, a->maxlength); a->maxlength = nl; a->vec = newDigitVec(&a->maxlength); } a->sign = b->sign; pa = a->vec; pb = b->vec; for (i = 0; i < pts; i++) pa[i] = 0; if (!bts) { for (i = 0; i < b->length; i++) pa[i + pts] = pb[i]; a->length = nl - 1; return; } accu = 0; for (i = 0; i < b->length; i++) { help = pb[i]; accu |= (help << bts); pa[i + pts] = accu; accu = help >> bleft; } pa[nl - 1] = accu; if (accu) a->length = nl; else a->length = nl - 1;} /* IasIslD */void IslasD(a, count) register pInteger a; DigitType count;/* Shift nach links */{ register DigitType accu, help, *pa, *pb; register int i; int pts, bts, bleft, nl, maxl; if (!a->length) return; pts = count / BitsPerDigit; nl = a->length + pts + 1; if (nl > a->maxlength) { pb = a->vec; maxl = nl; pa = newDigitVec(&maxl); } else { pa = pb = a->vec; } bts = count % BitsPerDigit; bleft = BitsPerDigit - bts; accu = 0; if (bts) { for (i = a->length - 1; i >= 0; i--) { help = pb[i]; accu |= (help >> bleft); pa[i + pts + 1] = accu; accu = help << bts; } pa[pts] = accu; } else { pa[nl - 1] = 0; for (i = a->length - 1; i >= 0; i--) pa[i + pts] = pb[i]; } for (i = pts - 1; i >= 0; i--) pa[i] = 0; if (nl > a->maxlength) { delDigitVec(a->vec, a->maxlength); a->vec = pa; a->maxlength = maxl; } if (pa[nl - 1]) a->length = nl; else a->length = nl - 1;} /* Islasint */BOOLEAN Isr1(a) register pInteger a;{ register int l; register BOOLEAN b; l = a->length; if (!l) return 0; b = DigitVecSr1(a->vec, l); l--; if (!a->vec[l]) a->length = l; return b;} /* Isr1 */BOOLEAN Ieven(a) register const Integer *a;{ return (!((*(a->vec)) & 1));} /* Ieven */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -