123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- // Bignum multiplication and division
- #include "stdafx.h"
- #include "defs.h"
- extern int ge(unsigned int *, unsigned int *, int);
- static void mulf(unsigned int *, unsigned int *, int, unsigned int);
- static void addf(unsigned int *, unsigned int *, int);
- static void subf(unsigned int *, unsigned int *, int);
- unsigned int *
- mmul(unsigned int *a, unsigned int *b)
- {
- int alen, blen, i, n;
- unsigned int *t, *x;
- if (MZERO(a) || MZERO(b))
- return mint(0);
- if (MLENGTH(a) == 1 && a[0] == 1) {
- t = mcopy(b);
- MSIGN(t) *= MSIGN(a);
- return t;
- }
- if (MLENGTH(b) == 1 && b[0] == 1) {
- t = mcopy(a);
- MSIGN(t) *= MSIGN(b);
- return t;
- }
- alen = MLENGTH(a);
- blen = MLENGTH(b);
- n = alen + blen;
- x = mnew(n);
- t = mnew(alen + 1);
- for (i = 0; i < n; i++)
- x[i] = 0;
- /* sum of partial products */
- for (i = 0; i < blen; i++) {
- mulf(t, a, alen, b[i]);
- addf(x + i, t, alen + 1);
- }
- mfree(t);
- /* length of product */
- for (i = n - 1; i > 0; i--)
- if (x[i])
- break;
- MLENGTH(x) = i + 1;
- MSIGN(x) = MSIGN(a) * MSIGN(b);
- return x;
- }
- unsigned int *
- mdiv(unsigned int *a, unsigned int *b)
- {
- int alen, blen, i, n;
- unsigned int c, *t, *x, *y;
- unsigned long long jj, kk;
- if (MZERO(b))
- stop("divide by zero");
- if (MZERO(a))
- return mint(0);
- alen = MLENGTH(a);
- blen = MLENGTH(b);
- n = alen - blen;
- if (n < 0)
- return mint(0);
- x = mnew(alen + 1);
- for (i = 0; i < alen; i++)
- x[i] = a[i];
- x[i] = 0;
- y = mnew(n + 1);
- t = mnew(blen + 1);
- /* Add 1 here to round up in case the remaining words are non-zero. */
- kk = (unsigned long long) b[blen - 1] + 1;
- for (i = 0; i <= n; i++) {
- y[n - i] = 0;
- for (;;) {
- /* estimate the partial quotient */
- if (little_endian()) {
- ((unsigned int *) &jj)[0] = x[alen - i - 1];
- ((unsigned int *) &jj)[1] = x[alen - i - 0];
- } else {
- ((unsigned int *) &jj)[1] = x[alen - i - 1];
- ((unsigned int *) &jj)[0] = x[alen - i - 0];
- }
- c = (unsigned int) (jj / kk);
- if (c == 0) {
- if (ge(x + n - i, b, blen)) { /* see note 1 */
- y[n - i]++;
- subf(x + n - i, b, blen);
- }
- break;
- }
- y[n - i] += c;
- mulf(t, b, blen, c);
- subf(x + n - i, t, blen + 1);
- }
- }
- mfree(t);
- mfree(x);
- /* length of quotient */
- for (i = n; i > 0; i--)
- if (y[i])
- break;
- if (i == 0 && y[0] == 0) {
- mfree(y);
- y = mint(0);
- } else {
- MLENGTH(y) = i + 1;
- MSIGN(y) = MSIGN(a) * MSIGN(b);
- }
- return y;
- }
- // a = a + b
- static void
- addf(unsigned int *a, unsigned int *b, int len)
- {
- int i;
- long long t = 0; /* can be signed or unsigned */
- for (i = 0; i < len; i++) {
- t += (long long) a[i] + b[i];
- a[i] = (unsigned int) t;
- t >>= 32;
- }
- }
- // a = a - b
- static void
- subf(unsigned int *a, unsigned int *b, int len)
- {
- int i;
- long long t = 0; /* must be signed */
- for (i = 0; i < len; i++) {
- t += (long long) a[i] - b[i];
- a[i] = (unsigned int) t;
- t >>= 32;
- }
- }
- // a = b * c
- // 0xffffffff + 0xffffffff * 0xffffffff == 0xffffffff00000000
- static void
- mulf(unsigned int *a, unsigned int *b, int len, unsigned int c)
- {
- int i;
- unsigned long long t = 0; /* must be unsigned */
- for (i = 0; i < len; i++) {
- t += (unsigned long long) b[i] * c;
- a[i] = (unsigned int) t;
- t >>= 32;
- }
- a[i] = (unsigned int) t;
- }
- unsigned int *
- mmod(unsigned int *a, unsigned int *b)
- {
- int alen, blen, i, n;
- unsigned int c, *t, *x, *y;
- unsigned long long jj, kk;
- if (MZERO(b))
- stop("divide by zero");
- if (MZERO(a))
- return mint(0);
- alen = MLENGTH(a);
- blen = MLENGTH(b);
- n = alen - blen;
- if (n < 0)
- return mcopy(a);
- x = mnew(alen + 1);
- for (i = 0; i < alen; i++)
- x[i] = a[i];
- x[i] = 0;
- y = mnew(n + 1);
- t = mnew(blen + 1);
- kk = (unsigned long long) b[blen - 1] + 1;
- for (i = 0; i <= n; i++) {
- y[n - i] = 0;
- for (;;) {
- /* estimate the partial quotient */
- if (little_endian()) {
- ((unsigned int *) &jj)[0] = x[alen - i - 1];
- ((unsigned int *) &jj)[1] = x[alen - i - 0];
- } else {
- ((unsigned int *) &jj)[1] = x[alen - i - 1];
- ((unsigned int *) &jj)[0] = x[alen - i - 0];
- }
- c = (int) (jj / kk);
- if (c == 0) {
- if (ge(x + n - i, b, blen)) { /* see note 1 */
- y[n - i]++;
- subf(x + n - i, b, blen);
- }
- break;
- }
- y[n - i] += c;
- mulf(t, b, blen, c);
- subf(x + n - i, t, blen + 1);
- }
- }
- mfree(t);
- mfree(y);
- /* length of remainder */
- for (i = blen - 1; i > 0; i--)
- if (x[i])
- break;
- if (i == 0 && x[0] == 0) {
- mfree(x);
- x = mint(0);
- } else {
- MLENGTH(x) = i + 1;
- MSIGN(x) = MSIGN(a);
- }
- return x;
- }
- // return both quotient and remainder of a/b
- void
- mdivrem(unsigned int **q, unsigned int **r, unsigned int *a, unsigned int *b)
- {
- int alen, blen, i, n;
- unsigned int c, *t, *x, *y;
- unsigned long long jj, kk;
- if (MZERO(b))
- stop("divide by zero");
- if (MZERO(a)) {
- *q = mint(0);
- *r = mint(0);
- return;
- }
- alen = MLENGTH(a);
- blen = MLENGTH(b);
- n = alen - blen;
- if (n < 0) {
- *q = mint(0);
- *r = mcopy(a);
- return;
- }
- x = mnew(alen + 1);
- for (i = 0; i < alen; i++)
- x[i] = a[i];
- x[i] = 0;
- y = mnew(n + 1);
- t = mnew(blen + 1);
- kk = (unsigned long long) b[blen - 1] + 1;
- for (i = 0; i <= n; i++) {
- y[n - i] = 0;
- for (;;) {
- /* estimate the partial quotient */
- if (little_endian()) {
- ((unsigned int *) &jj)[0] = x[alen - i - 1];
- ((unsigned int *) &jj)[1] = x[alen - i - 0];
- } else {
- ((unsigned int *) &jj)[1] = x[alen - i - 1];
- ((unsigned int *) &jj)[0] = x[alen - i - 0];
- }
- c = (int) (jj / kk);
- if (c == 0) {
- if (ge(x + n - i, b, blen)) { /* see note 1 */
- y[n - i]++;
- subf(x + n - i, b, blen);
- }
- break;
- }
- y[n - i] += c;
- mulf(t, b, blen, c);
- subf(x + n - i, t, blen + 1);
- }
- }
- mfree(t);
- /* length of quotient */
- for (i = n; i > 0; i--)
- if (y[i])
- break;
- if (i == 0 && y[0] == 0) {
- mfree(y);
- y = mint(0);
- } else {
- MLENGTH(y) = i + 1;
- MSIGN(y) = MSIGN(a) * MSIGN(b);
- }
- /* length of remainder */
- for (i = blen - 1; i > 0; i--)
- if (x[i])
- break;
- if (i == 0 && x[0] == 0) {
- mfree(x);
- x = mint(0);
- } else {
- MLENGTH(x) = i + 1;
- MSIGN(x) = MSIGN(a);
- }
- *q = y;
- *r = x;
- }
|