#include #include "..\h\config.h" #include "..\h\rt.h" #include "rproto.h" #include #ifdef LargeInts extern int over_flow; /* * Conventions: * * Bignums entering this module and leaving it are too large to * be represented with T_Integer. So, externally, a given value * is always T_Integer or always T_Bignum. * * Routines outside this module operate on bignums by calling * a routine like * * bigadd(da, db, dx) * * where da, db, and dx are pointers to tended descriptors. * For the common case where one argument is a T_Integer, these * call routines like * * bigaddi(da, IntVal(*db), dx). * * The bigxxxi routines can convert an integer to bignum form; * they use itobig. * * The routines that actually do the work take (length, address) * pairs specifying unsigned base-B digit strings. The sign handling * is done in the bigxxx routines. */ /* * Type for doing arithmetic on (2 * NB)-bit nonnegative numbers. * Normally unsigned but may be signed (with NB reduced appropriately) * if unsigned arithmetic is slow. */ /* The bignum radix, B */ #define B ((word)1 << NB) /* Bignum digits in a word */ #define WORDLEN (WordBits / NB + (WordBits % NB != 0)) /* size of a bignum block that will hold an integer */ #define INTBIGBLK sizeof(struct b_bignum) + sizeof(DIGIT) * WORDLEN /* lo(uword d) : the low digit of a uword hi(uword d) : the rest, d is unsigned signed_hi(uword d) : the rest, d is signed dbl(DIGIT a, DIGIT b) : the two-digit uword [a,b] */ #define lo(d) ((d) & (B - 1)) #define hi(d) ((uword)(d) >> NB) #define dbl(a,b) (((uword)(a) << NB) + (b)) #if ((-1) >> 1) < 0 #define signed_hi(d) ((word)(d) >> NB) #else #define signbit ((uword)1 << (WordBits - NB - 1)) #define signed_hi(d) ((word)((((uword)(d) >> NB) ^ signbit) - signbit)) #endif /* BigNum(dptr dp) : the struct b_bignum pointed to by dp */ #define BigNum(dp) ((struct b_bignum *)&BlkLoc(*dp)->bignumblk) /* LEN(struct b_bignum *b) : number of significant digits */ #define LEN(b) ((b)->lsd - (b)->msd + 1) /* DIG(struct b_bignum *b, word i): pointer to ith most significant digit */ #define DIG(b,i) (&(b)->digits[(b)->msd+(i)]) /* ceil, ln: ceil may be 1 too high in case ln is inaccurate */ #undef ceil #define ceil(x) ((word)((x) + 1.01)) #define ln(n) (log((double)n)) /* determine the number of words needed for a bignum block with n digits */ #define BigNeed(n) ( ((sizeof(struct b_bignum) + ((n) - 1) * sizeof(DIGIT)) \ + WordSize - 1) & -WordSize ) /* copied from rconv.c */ #if !EBCDIC #define tonum(c) (isdigit(c) ? (c)-'0' : 10+(((c)|(040))-'a')) #else /* !EBCDIC */ int tonum(c) int c; { #ifdef SASC const static char *alphanum = "0123456789abcdefghijklmnopqrstuvwxyz" ; char *where; where = memchr(alphanum, tolower(c), 36); if (where == 0) return -1; return where - alphanum; #else /* SASC */ if(isdigit(c)) return (c - '0'); if( (c | ' ') >= 'A' & (c | ' ') <= 'I') return( c - 'A' ); if( (c | ' ') >= 'J' & (c | ' ') <= 'R') return( (c - 'J') + 9 ); if( (c | ' ') >= 'S' & (c | ' ') <= 'Z') return( (c - 'S') + 18 ); return 0; #endif /* SASC */ } #endif /* !EBCDIC */ /* copied from oref.c */ #define RandVal (RanScale*(k_random=(RandA*(long)k_random+RandC)&0x7fffffffL)) hidden int mkdesc Params((struct b_bignum *x, dptr dx)); hidden novalue itobig Params((word i, struct b_bignum *x, dptr dx)); hidden novalue decout Params((FILE *f, DIGIT *n, word l)); hidden int bigaddi Params((dptr da, word i, dptr dx)); hidden int bigsubi Params((dptr da, word i, dptr dx)); hidden int bigmuli Params((dptr da, word i, dptr dx)); hidden int bigdivi Params((dptr da, word i, dptr dx)); hidden int bigmodi Params((dptr da, word i, dptr dx)); hidden int bigpowi Params((dptr da, word i, dptr dx)); hidden int bigpowii Params((word a, word i, dptr dx)); hidden word bigcmpi Params((dptr da, word i)); hidden DIGIT add1 Params((DIGIT *u, DIGIT *v, DIGIT *w, word n)); hidden word sub1 Params((DIGIT *u, DIGIT *v, DIGIT *w, word n)); hidden novalue mul1 Params((DIGIT *u, DIGIT *v, DIGIT *w, word n, word m)); hidden novalue div1 Params((DIGIT *a, DIGIT *b, DIGIT *q, DIGIT *r, word m, word n)); hidden novalue compl1 Params((DIGIT *u, DIGIT *w, word n)); hidden word cmp1 Params((DIGIT *u, DIGIT *v, word n)); hidden DIGIT addi1 Params((DIGIT *u, word k, DIGIT *w, word n)); hidden novalue subi1 Params((DIGIT *u, word k, DIGIT *w, word n)); hidden DIGIT muli1 Params((DIGIT *u, word k, int c, DIGIT *w, word n)); hidden DIGIT divi1 Params((DIGIT *u, word k, DIGIT *w, word n)); hidden DIGIT shifti1 Params((DIGIT *u, word k, DIGIT c, DIGIT *w, word n)); hidden word cmpi1 Params((DIGIT *u, word k, word n)); hidden novalue bdzero Params((DIGIT *dest, word l)); hidden novalue bdcopy Params((DIGIT *src, DIGIT *dest, word l)); /* * mkdesc -- put value into a descriptor */ static int mkdesc(x, dx) struct b_bignum *x; dptr dx; { word xlen, cmp; static DIGIT maxword[WORDLEN] = { 1 << ((WordBits - 1) % NB) }; /* suppress leading zero digits */ while (x->msd != x->lsd && *DIG(x,0) == 0) x->msd++; /* put it into a word if it fits, otherwise return the bignum */ xlen = LEN(x); if (xlen < WORDLEN || (xlen == WORDLEN && ((cmp = cmp1(DIG(x,0), maxword, WORDLEN)) < 0 || (cmp == (word)0 && x->sign)))) { word val = -(word)*DIG(x,0); word i; for (i = x->msd; ++i <= x->lsd; ) val = (val << NB) - x->digits[i]; if (!x->sign) val = -val; dx->dword = D_Integer; IntVal(*dx) = val; } else { dx->dword = D_Bignum; BlkLoc(*dx) = (union block *)x; } return Success; } /* * i -> big */ static novalue itobig(i, x, dx) word i; struct b_bignum *x; dptr dx; { x->lsd = WORDLEN - 1; x->msd = WORDLEN; x->sign = 0; if (i == 0) { x->msd--; *DIG(x,0) = 0; } else if (i < 0) { word d = lo(i); if (d != 0) { d = B - d; i += B; } i = - signed_hi(i); x->msd--; *DIG(x,0) = d; x->sign = 1; } while (i != 0) { x->msd--; *DIG(x,0) = lo(i); i = hi(i); } dx->dword = D_Bignum; BlkLoc(*dx) = (union block *)x; } /* * string -> bignum */ word bigradix(sign, r, s, dx) int sign; /* '-' or not */ int r; /* radix 2 .. 36 */ char *s; /* input string */ dptr dx; /* output T_Integer or T_Bignum */ { struct b_bignum *b; DIGIT *bd; word len; int c; if (r == 0) return CvtFail; len = ceil(strlen(s) * ln(r) / ln(B)); if (blkreq(BigNeed(len)) == Error) return CvtFail; b = alcbignum(len); bd = DIG(b,0); bdzero(bd, len); if (r < 2 || r > 36) return CvtFail; for (c = *s++; isalnum(c); c = *s++) { c = tonum(c); if (c >= r) return CvtFail; muli1(bd, (word)r, c, bd, len); } while (isspace(c)) c = *s++; if (c != '\0') return CvtFail; if (sign == '-') b->sign = 1; /* put value into dx and return the type */ (void)mkdesc(b, dx); return Type(*dx); } /* * bignum -> real */ double bigtoreal(da) dptr da; { word i; double r = 0; struct b_bignum *b = &BlkLoc(*da)->bignumblk; for (i = b->msd; i <= b->lsd; i++) r = r * B + b->digits[i]; return (b->sign ? -r : r); } /* * real -> bignum */ int realtobig(da, dx) dptr da, dx; { double x = BlkLoc(*da)->realblk.realval; struct b_bignum *b; word i, blen; word d; if (x > 0.9999 * MinLong && x < 0.9999 * MaxLong) { MakeInt((word)x, dx); return Success; /* got lucky; a simple integer suffices */ } x = x > 0 ? x : -x; blen = ln(x) / ln(B) + 0.99; for (i = 0; i < blen; i++) x /= B; if (x >= 1.0) { x /= B; blen += 1; } if (blkreq(BigNeed(blen)) == Error) return Error; b = alcbignum(blen); for (i = 0; i < blen; i++) { d = (x *= B); *DIG(b,i) = d; x -= d; } b->sign = x < 0; return mkdesc(b, dx); } /* * bignum -> string */ int bigtos(da, dx) dptr da, dx; { struct b_bignum *a, *temp; word alen = LEN(BigNum(da)); word slen = ceil(alen * ln(B) / ln(10)); char *p, *q; if (strreq(slen) == Error || blkreq(BigNeed(alen)) == Error) return CvtFail; a = BigNum(da); temp = alcbignum(alen); if (a->sign) slen++; q = alcstr("",slen); bdcopy(DIG(a,0), DIG(temp,0), alen); p = q += slen; while (cmpi1(DIG(temp,0), (word)0, alen)) *--p = '0' + divi1(DIG(temp,0), (word)10, DIG(temp,0), alen); if (a->sign) *--p = '-'; StrLen(*dx) = q - p; StrLoc(*dx) = p; return Cvt; } /* * bignum -> file */ novalue bigprint(f, da) FILE *f; dptr da; { struct b_bignum *a, *temp; word alen = LEN(BigNum(da)); word slen, dlen; slen = (BlkLoc(*da)->bignumblk.lsd - BlkLoc(*da)->bignumblk.msd + 1); dlen = slen * NB * 0.3010299956639812; /* 1 / log2(10) */ if (dlen > MaxDigits) { fprintf(f, "integer(~%ld)",dlen - 2); /* center estimate */ return; } if (blkreq(BigNeed(alen)) == Error) { fatalerr(0, NULL); /* not worth passing this one back */ } temp = alcbignum(alen); a = BigNum(da); bdcopy(DIG(a,0), DIG(temp,0), alen); if (a->sign) putc('-', f); decout(f, DIG(temp,0), alen); } static novalue decout(f, n, l) FILE *f; DIGIT *n; word l; { word i = divi1(n, (word)10, n, l); if (cmpi1(n, (word)0, l)) decout(f, n, l); putc('0' + i, f); } /* * da -> dx */ int cpbignum(da, dx) dptr da, dx; { struct b_bignum *a; word alen = LEN(BigNum(da)); struct b_bignum *x; if (blkreq(BigNeed(alen)) == Error) return Error; x = alcbignum(alen); a = BigNum(da); bdcopy(DIG(a,0), DIG(x,0), alen); x->sign = a->sign; return mkdesc(x, dx); } /* * da + db -> dx */ int bigadd(da, db, dx) dptr da, db; dptr dx; { struct b_bignum *x, *a, *b; word alen, blen; word c; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); if (blkreq(BigNeed(alen > blen ? alen + 1 : blen + 1)) == Error) return Error; a = BigNum(da); b = BigNum(db); if (a->sign == b->sign) { if (alen > blen) { x = alcbignum(alen + 1); c = add1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen+1), blen); *DIG(x,0) = addi1(DIG(a,0), c, DIG(x,1), alen-blen); } else if (alen == blen) { x = alcbignum(alen + 1); *DIG(x,0) = add1(DIG(a,0), DIG(b,0), DIG(x,1), alen); } else { x = alcbignum(blen + 1); c = add1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen+1), alen); *DIG(x,0) = addi1(DIG(b,0), c, DIG(x,1), blen-alen); } x->sign = a->sign; } else { if (alen > blen) { x = alcbignum(alen); c = sub1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen), blen); subi1(DIG(a,0), -c, DIG(x,0), alen-blen); x->sign = a->sign; } else if (alen == blen) { x = alcbignum(alen); if (cmp1(DIG(a,0), DIG(b,0), alen) > 0) { (void)sub1(DIG(a,0), DIG(b,0), DIG(x,0), alen); x->sign = a->sign; } else { (void)sub1(DIG(b,0), DIG(a,0), DIG(x,0), alen); x->sign = b->sign; } } else { x = alcbignum(blen); c = sub1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen), alen); subi1(DIG(b,0), -c, DIG(x,0), blen-alen); x->sign = b->sign; } } return mkdesc(x, dx); } else if (Type(*da) == T_Bignum) /* bignum + integer */ return bigaddi(da, IntVal(*db), dx); else if (Type(*db) == T_Bignum) /* integer + bignum */ return bigaddi(db, IntVal(*da), dx); else { /* integer + integer */ struct descrip td; char tdigits[INTBIGBLK]; itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); return bigaddi(&td, IntVal(*db), dx); } } /* * da - db -> dx */ int bigsub(da, db, dx) dptr da, db, dx; { struct descrip td; char tdigits[INTBIGBLK]; struct b_bignum *a, *b, *x; word alen, blen; word c; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); if (blkreq(BigNeed(alen > blen ? alen + 1 : blen + 1)) == Error) return Error; a = BigNum(da); b = BigNum(db); if (a->sign != b->sign) { if (alen > blen) { x = alcbignum(alen + 1); c = add1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen+1), blen); *DIG(x,0) = addi1(DIG(a,0), c, DIG(x,1), alen-blen); } else if (alen == blen) { x = alcbignum(alen + 1); *DIG(x,0) = add1(DIG(a,0), DIG(b,0), DIG(x,1), alen); } else { x = alcbignum(blen + 1); c = add1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen+1), alen); *DIG(x,0) = addi1(DIG(b,0), c, DIG(x,1), blen-alen); } x->sign = a->sign; } else { if (alen > blen) { x = alcbignum(alen); c = sub1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen), blen); subi1(DIG(a,0), -c, DIG(x,0), alen-blen); x->sign = a->sign; } else if (alen == blen) { x = alcbignum(alen); if (cmp1(DIG(a,0), DIG(b,0), alen) > 0) { (void)sub1(DIG(a,0), DIG(b,0), DIG(x,0), alen); x->sign = a->sign; } else { (void)sub1(DIG(b,0), DIG(a,0), DIG(x,0), alen); x->sign = 1 ^ b->sign; } } else { x = alcbignum(blen); c = sub1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen), alen); subi1(DIG(b,0), -c, DIG(x,0), blen-alen); x->sign = 1 ^ b->sign; } } return mkdesc(x, dx); } else if (Type(*da) == T_Bignum) /* bignum - integer */ return bigsubi(da, IntVal(*db), dx); else if (Type(*db) == T_Bignum) { /* integer - bignum */ itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(&td)); blen = LEN(BigNum(db)); if (blkreq(BigNeed(alen > blen ? alen + 1 : blen + 1)) == Error) return Error; a = BigNum(&td); b = BigNum(db); if (a->sign != b->sign) { if (alen == blen) { x = alcbignum(alen + 1); *DIG(x,0) = add1(DIG(a,0), DIG(b,0), DIG(x,1), alen); } else { x = alcbignum(blen + 1); c = add1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen+1), alen); *DIG(x,0) = addi1(DIG(b,0), c, DIG(x,1), blen-alen); } x->sign = a->sign; } else { if (alen == blen) { x = alcbignum(alen); if (cmp1(DIG(a,0), DIG(b,0), alen) > 0) { (void)sub1(DIG(a,0), DIG(b,0), DIG(x,0), alen); x->sign = a->sign; } else { (void)sub1(DIG(b,0), DIG(a,0), DIG(x,0), alen); x->sign = 1 ^ b->sign; } } else { x = alcbignum(blen); c = sub1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen), alen); subi1(DIG(b,0), -c, DIG(x,0), blen-alen); x->sign = 1 ^ b->sign; } } return mkdesc(x, dx); } else { /* integer - integer */ itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); return bigsubi(&td, IntVal(*db), dx); } } /* * da * db -> dx */ int bigmul(da, db, dx) dptr da, db, dx; { struct b_bignum *a, *b, *x; word alen, blen; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); if (blkreq(BigNeed(alen + blen)) == Error) return Error; a = BigNum(da); b = BigNum(db); x = alcbignum(alen + blen); mul1(DIG(a,0), DIG(b,0), DIG(x,0), alen, blen); x->sign = a->sign ^ b->sign; return mkdesc(x, dx); } else if (Type(*da) == T_Bignum) /* bignum * integer */ return bigmuli(da, IntVal(*db), dx); else if (Type(*db) == T_Bignum) /* integer * bignum */ return bigmuli(db, IntVal(*da), dx); else { /* integer * integer */ struct descrip td; char tdigits[INTBIGBLK]; itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); return bigmuli(&td, IntVal(*db), dx); } } /* * da / db -> dx */ int bigdiv(da, db, dx) dptr da, db, dx; { struct b_bignum *a, *b, *x; word alen, blen; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); if (alen < blen) { MakeInt(0, dx); return Success; } if (blkreq(BigNeed(alen-blen+1)+BigNeed(alen+1)+BigNeed(blen)) == Error) return Error; a = BigNum(da); b = BigNum(db); x = alcbignum(alen - blen + 1); if (blen == 1) divi1(DIG(a,0), (word)*DIG(b,0), DIG(x,0), alen); else div1(DIG(a,0), DIG(b,0), DIG(x,0), NULL, alen-blen, blen); x->sign = a->sign ^ b->sign; return mkdesc(x, dx); } else if (Type(*da) == T_Bignum) /* bignum / integer */ return bigdivi(da, IntVal(*db), dx); else if (Type(*db) == T_Bignum) { /* integer / bignum */ MakeInt(0, dx); return Success; } /* not called for integer / integer */ } /* * da % db -> dx */ int bigmod(da, db, dx) dptr da, db, dx; { struct b_bignum *a, *b, *x, *temp; word alen, blen; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); if (alen < blen) { cpbignum(da, dx); return Success; } if (blkreq(BigNeed(blen)+BigNeed(alen+1)+BigNeed(blen)) == Error) return Error; a = BigNum(da); b = BigNum(db); x = alcbignum(blen); if (blen == 1) { temp = alcbignum(alen); *DIG(x,0) = divi1(DIG(a,0), (word)*DIG(b,0), DIG(temp,0), alen); } else div1(DIG(a,0), DIG(b,0), NULL, DIG(x,0), alen-blen, blen); x->sign = a->sign; return mkdesc(x, dx); } else if (Type(*da) == T_Bignum) /* bignum % integer */ return bigmodi(da, IntVal(*db), dx); else if (Type(*db) == T_Bignum) { /* integer % bignum */ struct descrip td; char tdigits[INTBIGBLK]; itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); cpbignum(&td, dx); return Success; } /* not called for integer % integer */ } /* * -i -> dx */ int bigneg(da, dx) dptr da, dx; { struct descrip td; char tdigits[INTBIGBLK]; itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); BigNum(&td)->sign ^= 1; return cpbignum(&td, dx); } /* * da ^ db -> dx */ int bigpow(da, db, dx) dptr da, db, dx; { word n; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { if (BigNum(db)->sign) { MakeInt(0, dx); } else { n = LEN(BigNum(db)) * NB; /* scan bits left to right. skip leading 1. */ while (--n >= 0) if ((*DIG(BigNum(db), n / NB) & (1 << (n % NB)))) break; /* then, for each zero, square the partial result; * for each one, square it and multiply it by a */ *dx = *da; while (--n >= 0) { if (bigmul(dx, dx, dx) == Error) return Error; if ((*DIG(BigNum(db), n / NB) & (1 << (n % NB)))) if (bigmul(dx, da, dx) == Error) return Error; } } return Success; } else if (Type(*da) == T_Bignum) /* bignum ^ integer */ return bigpowi(da, IntVal(*db), dx); else if (Type(*db) == T_Bignum) /* integer ^ bignum */ return bigpowii(IntVal(*da), (word)bigtoreal(db), dx); else /* integer ^ integer */ return bigpowii(IntVal(*da), IntVal(*db), dx); } /* * iand(da, db) -> dx */ int bigand(da, db, dx) dptr da, db, dx; { struct b_bignum *a, *b, *x; word alen, blen, xlen; word i; struct b_bignum *tad, *tbd; DIGIT *ad, *bd; struct descrip td; char tdigits[INTBIGBLK]; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(xlen)) == Error) return Error; a = BigNum(da); b = BigNum(db); x = alcbignum(xlen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] & bd[i]; if (a->sign & b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } else if (Type(*da) == T_Bignum) { /* iand(bignum,integer) */ itobig(IntVal(*db), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(da)); blen = LEN(BigNum(&td)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(alen)) == Error) return Error; a = BigNum(da); b = BigNum(&td); x = alcbignum(alen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] & bd[i]; if (a->sign & b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } else if (Type(*db) == T_Bignum) { /* iand(integer,bignum) */ itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(&td)); blen = LEN(BigNum(db)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(blen)) == Error) return Error; a = BigNum(&td); b = BigNum(db); x = alcbignum(blen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] & bd[i]; if (a->sign & b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } /* not called for iand(integer,integer) */ return mkdesc(x, dx); } /* * ior(da, db) -> dx */ int bigor(da, db, dx) dptr da, db, dx; { struct b_bignum *a, *b, *x; word alen, blen, xlen; word i; struct b_bignum *tad, *tbd; DIGIT *ad, *bd; struct descrip td; char tdigits[INTBIGBLK]; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(xlen)) == Error) return Error; a = BigNum(da); b = BigNum(db); x = alcbignum(xlen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] | bd[i]; if (a->sign | b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } else if (Type(*da) == T_Bignum) { /* ior(bignum,integer) */ itobig(IntVal(*db), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(da)); blen = LEN(BigNum(&td)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(alen)) == Error) return Error; a = BigNum(da); b = BigNum(&td); x = alcbignum(alen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] | bd[i]; if (a->sign | b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } else if (Type(*db) == T_Bignum) { /* ior(integer,bignym) */ itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(&td)); blen = LEN(BigNum(db)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(blen)) == Error) return Error; a = BigNum(&td); b = BigNum(db); x = alcbignum(blen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] | bd[i]; if (a->sign | b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } /* not called for ior(integer,integer) */ return mkdesc(x, dx); } /* * xor(da, db) -> dx */ int bigxor(da, db, dx) dptr da, db, dx; { struct b_bignum *a, *b, *x; word alen, blen, xlen; word i; struct b_bignum *tad, *tbd; DIGIT *ad, *bd; struct descrip td; char tdigits[INTBIGBLK]; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { alen = LEN(BigNum(da)); blen = LEN(BigNum(db)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(xlen)) == Error) return Error; a = BigNum(da); b = BigNum(db); x = alcbignum(xlen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] ^ bd[i]; if (a->sign ^ b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } else if (Type(*da) == T_Bignum) { /* ixor(bignum,integer) */ itobig(IntVal(*db), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(da)); blen = LEN(BigNum(&td)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(alen)) == Error) return Error; a = BigNum(da); b = BigNum(&td); x = alcbignum(alen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] ^ bd[i]; if (a->sign ^ b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } else if (Type(*db) == T_Bignum) { /* ixor(integer,bignum) */ itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(&td)); blen = LEN(BigNum(db)); xlen = alen > blen ? alen : blen; if (blkreq(3 * BigNeed(blen)) == Error) return Error; a = BigNum(&td); b = BigNum(db); x = alcbignum(blen); if (alen == xlen && !a->sign) ad = DIG(a,0); else { tad = alcbignum(xlen); ad = DIG(tad,0); bdzero(ad, xlen - alen); bdcopy(DIG(a,0), &ad[xlen-alen], alen); if (a->sign) compl1(ad, ad, xlen); } if (blen == xlen && !b->sign) bd = DIG(b,0); else { tbd = alcbignum(xlen); bd = DIG(tbd,0); bdzero(bd, xlen - blen); bdcopy(DIG(b,0), &bd[xlen-blen], blen); if (b->sign) compl1(bd, bd, xlen); } for (i = 0; i < xlen; i++) *DIG(x,i) = ad[i] ^ bd[i]; if (a->sign ^ b->sign) { x->sign = 1; compl1(DIG(x,0), DIG(x,0), xlen); } } /* not called for ixor(integer,integer) */ return mkdesc(x, dx); } /* * bigshift(da, db) -> dx */ int bigshift(da, db, dx) dptr da, db, dx; { struct b_bignum *a, *x; word alen; word r = IntVal(*db) % NB; word q = (r >= 0 ? IntVal(*db) : (IntVal(*db) - (r += NB))) / NB; word xlen; struct b_bignum *tad; DIGIT *ad; if (Type(*da) == T_Bignum) { alen = LEN(BigNum(da)); xlen = alen + q + 1; if (xlen <= 0) { MakeInt(0, dx); return Success; } else { if (blkreq(BigNeed(xlen) + BigNeed(alen)) == Error) return Error; a = BigNum(da); x = alcbignum(xlen); ad = DIG(a,0); if (q >= 0) { *DIG(x,0) = shifti1(ad, r, (DIGIT)0, DIG(x,1), alen); bdzero(DIG(x,alen+1), q); x->sign = a->sign; } else { *DIG(x,0) = shifti1(ad, r, ad[alen+q] >> (NB-r), DIG(x,1), alen+q); } return mkdesc(x, dx); } } else { /* da is integer */ struct descrip td; char tdigits[INTBIGBLK]; itobig(IntVal(*da), (struct b_bignum *)tdigits, &td); alen = LEN(BigNum(&td)); xlen = alen + q + 1; if (xlen <= 0) { MakeInt(0, dx); return Success; } else { if (blkreq(BigNeed(xlen) + BigNeed(alen)) == Error) return Error; a = BigNum(&td); x = alcbignum(xlen); ad = DIG(a,0); if (q >= 0) { *DIG(x,0) = shifti1(ad, r, (DIGIT)0, DIG(x,1), alen); bdzero(DIG(x,alen+1), q); x->sign = a->sign; } else *DIG(x,0) = shifti1(ad, r, ad[alen+q] >> (NB-r), DIG(x,1), alen+q); return mkdesc(x, dx); } } } /* * negative if da < db * zero if da == db * positive if da > db */ word bigcmp(da, db) dptr da, db; { struct b_bignum *a = BigNum(da); struct b_bignum *b = BigNum(db); word alen, blen; if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) { if (a->sign != b->sign) return (b->sign - a->sign); alen = LEN(a); blen = LEN(b); if (alen != blen) return (a->sign ? blen - alen : alen - blen); if (a->sign) return cmp1(DIG(b,0), DIG(a,0), alen); else return cmp1(DIG(a,0), DIG(b,0), alen); } else if (Type(*da) == T_Bignum) /* cmp(bignum, integer) */ return bigcmpi(da, IntVal(*db)); else /* cmp(integer, bignum) */ return -bigcmpi(db, IntVal(*da)); } /* * ?da -> dx */ int bigrand(da, dx) dptr da, dx; { struct b_bignum *a; word alen = LEN(BigNum(da)); struct b_bignum *x; struct b_bignum *td; DIGIT *d; word i; double rval; if (blkreq(4 * BigNeed(alen + 1) + 4) == Error) return Error; x = alcbignum(alen); td = alcbignum(alen + 1); d = DIG(td,0); a = BigNum(da); for (i = alen; i >= 0; i--) { rval = RandVal; d[i] = rval * B; } div1(d, DIG(a,0), NULL, DIG(x,0), (word)1, alen); addi1(DIG(x,0), (word)1, DIG(x,0), alen); return mkdesc(x, dx); } /* * da + i -> dx */ static int bigaddi(da, i, dx) dptr da, dx; word i; { struct b_bignum *a, *x; word alen; if (i < 0) return bigsubi(da, -i, dx); else if (i != (DIGIT)i) { struct descrip td; char tdigits[INTBIGBLK]; itobig(i, (struct b_bignum *)tdigits, &td); return bigadd(da, &td, dx); } else { alen = LEN(BigNum(da)); if (blkreq(BigNeed(alen + 1)) == Error) return Error; a = BigNum(da); if (a->sign) { x = alcbignum(alen); subi1(DIG(a,0), i, DIG(x,0), alen); } else { x = alcbignum(alen + 1); *DIG(x,0) = addi1(DIG(a,0), i, DIG(x,1), alen); } x->sign = a->sign; return mkdesc(x, dx); } } /* * da - i -> dx */ static int bigsubi(da, i, dx) dptr da, dx; word i; { struct b_bignum *a, *x; word alen; if (i < 0) return bigaddi(da, -i, dx); else if (i != (DIGIT)i) { struct descrip td; char tdigits[INTBIGBLK]; itobig(i, (struct b_bignum *)tdigits, &td); return bigsub(da, &td, dx); } else { alen = LEN(BigNum(da)); if (blkreq(BigNeed(alen + 1)) == Error) return Error; a = BigNum(da); if (a->sign) { x = alcbignum(alen + 1); *DIG(x,0) = addi1(DIG(a,0), i, DIG(x,1), alen); } else { x = alcbignum(alen); subi1(DIG(a,0), i, DIG(x,0), alen); } x->sign = a->sign; return mkdesc(x, dx); } } /* * da * i -> dx */ static int bigmuli(da, i, dx) dptr da, dx; word i; { struct b_bignum *a, *x; word alen; if (i <= -B || i >= B) { struct descrip td; char tdigits[INTBIGBLK]; itobig(i, (struct b_bignum *)tdigits, &td); return bigmul(da, &td, dx); } else { alen = LEN(BigNum(da)); if (blkreq(BigNeed(alen + 1)) == Error) return Error; a = BigNum(da); x = alcbignum(alen + 1); if (i >= 0) x->sign = a->sign; else { x->sign = 1 ^ a->sign; i = -i; } *DIG(x,0) = muli1(DIG(a,0), i, 0, DIG(x,1), alen); return mkdesc(x, dx); } } /* * da / i -> dx */ static int bigdivi(da, i, dx) dptr da, dx; word i; { struct b_bignum *a, *x; word alen; if (i <= -B || i >= B) { struct descrip td; char tdigits[INTBIGBLK]; itobig(i, (struct b_bignum *)tdigits, &td); return bigdiv(da, &td, dx); } else { alen = LEN(BigNum(da)); if (blkreq(BigNeed(alen)) == Error) return Error; a = BigNum(da); x = alcbignum(alen); if (i >= 0) x->sign = a->sign; else { x->sign = 1 ^ a->sign; i = -i; } divi1(DIG(a,0), i, DIG(x,0), alen); return mkdesc(x, dx); } } /* * da % i -> dx */ static int bigmodi(da, i, dx) dptr da, dx; word i; { struct b_bignum *a, *temp; word alen; word x; if (i <= -B || i >= B) { struct descrip td; char tdigits[INTBIGBLK]; itobig(i, (struct b_bignum *)tdigits, &td); return bigmod(da, &td, dx); } else { alen = LEN(BigNum(da)); if (blkreq(BigNeed(alen)) == Error) return Error; a = BigNum(da); temp = alcbignum(alen); x = divi1(DIG(a,0), Abs(i), DIG(temp,0), alen); if (a->sign) x = -x; MakeInt(x, dx); return Success; } } /* * da ^ i -> dx */ static int bigpowi(da, i, dx) dptr da, dx; word i; { int n = WordBits; if (i > 0) { /* scan bits left to right. skip leading 1. */ while (--n >= 0) if (i & ((word)1 << n)) break; /* then, for each zero, square the partial result; for each one, square it and multiply it by a */ *dx = *da; while (--n >= 0) { if (bigmul(dx, dx, dx) == Error) return Error; if (i & ((word)1 << n)) if (bigmul(dx, da, dx) == Error) return Error; } } else { MakeInt(0, dx); } return Success; } /* * a ^ i -> dx */ static int bigpowii(a, i, dx) word a, i; dptr dx; { word x, y; int n = WordBits; int isbig = 0; if (a == 0 || i <= 0) { /* special cases */ if (a == 0 && i <= 0) /* 0 ^ negative -> error */ RetError(-204, nulldesc); if (a == -1) { /* -1 ^ [odd,even] -> [-1,+1] */ if (!(i & 1)) a = 1; } else if (a != 1) { /* 1 ^ any -> 1 */ a = 0; } /* others ^ negative -> 0 */ MakeInt(a, dx); } else { struct descrip td; char tdigits[INTBIGBLK]; /* scan bits left to right. skip leading 1. */ while (--n >= 0) if (i & ((word)1 << n)) break; /* then, for each zero, square the partial result; for each one, square it and multiply it by a */ x = a; while (--n >= 0) { if (isbig) { if (bigmul(dx, dx, dx) == Error) return Error; } else { y = mul(x, x); if (!over_flow) x = y; else { itobig(x, (struct b_bignum *)tdigits, &td); if (bigmul(&td, &td, dx) == Error) return Error; isbig = (Type(*dx) == T_Bignum); } } if (i & ((word)1 << n)) { if (isbig) { if (bigmuli(dx, a, dx) == Error) return Error; } else { y = mul(x, a); if (!over_flow) x = y; else { itobig(x, (struct b_bignum *)tdigits, &td); if (bigmuli(&td, a, dx) == Error) return Error; isbig = (Type(*dx) == T_Bignum); } } } } if (!isbig) { MakeInt(x, dx); } } return Success; } /* * negative if da < i * zero if da == i * positive if da > i */ static word bigcmpi(da, i) dptr da; word i; { struct b_bignum *a = BigNum(da); word alen = LEN(a); if (i > -B && i < B) { if (i >= 0) if (a->sign) return -1; else return cmpi1(DIG(a,0), i, alen); else if (a->sign) return -cmpi1(DIG(a,0), -i, alen); else return 1; } else { struct descrip td; char tdigits[INTBIGBLK]; itobig(i, (struct b_bignum *)tdigits, &td); return bigcmp(da, &td); } } /* These are all straight out of Knuth vol. 2, Sec. 4.3.1. */ /* * (u,n) + (v,n) -> (w,n) * * returns carry, 0 or 1 */ static DIGIT add1(u, v, w, n) DIGIT *u, *v, *w; word n; { uword dig, carry; word i; carry = 0; for (i = n; --i >= 0; ) { dig = (uword)u[i] + v[i] + carry; w[i] = lo(dig); carry = hi(dig); } return carry; } /* * (u,n) - (v,n) -> (w,n) * * returns carry, 0 or -1 */ static word sub1(u, v, w, n) DIGIT *u, *v, *w; word n; { uword dig, carry; word i; carry = 0; for (i = n; --i >= 0; ) { dig = (uword)u[i] - v[i] + carry; w[i] = lo(dig); carry = signed_hi(dig); } return carry; } /* * (u,n) * (v,m) -> (w,m+n) */ static novalue mul1(u, v, w, n, m) DIGIT *u, *v, *w; word n, m; { word i, j; uword dig, carry; bdzero(&w[m], n); for (j = m; --j >= 0; ) { carry = 0; for (i = n; --i >= 0; ) { dig = (uword)u[i] * v[j] + w[i+j+1] + carry; w[i+j+1] = lo(dig); carry = hi(dig); } w[j] = carry; } } /* * (a,m+n) / (b,n) -> (q,m+1) (r,n) * * if q or r is NULL, the quotient or remainder is discarded */ static novalue div1(a, b, q, r, m, n) DIGIT *a, *b, *q, *r; word m, n; { uword qhat, rhat; uword dig, carry; struct b_bignum *tu, *tv; DIGIT *u, *v; word d; word i, j; /* blkreq's done in calling routines */ tu = alcbignum(m + n + 1); tv = alcbignum(n); u = DIG(tu,0); v = DIG(tv,0); /* D1 */ for (d = 0; d < NB; d++) if (b[0] & (1 << (NB - 1 - d))) break; u[0] = shifti1(a, d, (DIGIT)0, &u[1], m+n); shifti1(b, d, (DIGIT)0, v, n); /* D2, D7 */ for (j = 0; j <= m; j++) { /* D3 */ if (u[j] == v[0]) { qhat = B - 1; rhat = (uword)v[0] + u[j+1]; } else { uword numerator = dbl(u[j], u[j+1]); qhat = numerator / (uword)v[0]; rhat = numerator % (uword)v[0]; } while (rhat < B && qhat * v[1] > dbl(rhat, u[j+2])) { qhat -= 1; rhat += v[0]; } /* D4 */ carry = 0; for (i = n; i > 0; i--) { dig = u[i+j] - v[i-1] * qhat + carry; /* -BSQ+B .. B-1 */ u[i+j] = lo(dig); if ((uword)dig < B) carry = hi(dig); else carry = hi(dig) | -B; } carry = (word)(carry + u[j]) < 0; /* D5 */ if (q) q[j] = qhat; /* D6 */ if (carry) { if (q) q[j] -= 1; carry = 0; for (i = n; i > 0; i--) { dig = (uword)u[i+j] + v[i-1] + carry; u[i+j] = lo(dig); carry = hi(dig); } } } if (r) { if (d == 0) shifti1(&u[m+1], (word)d, (DIGIT)0, r, n); else r[0] = shifti1(&u[m+1], (word)(NB - d), u[m+n]>>d, &r[1], n - 1); } } /* * - (u,n) -> (w,n) * */ static novalue compl1(u, w, n) DIGIT *u, *w; word n; { uword dig, carry = 0; word i; for (i = n; --i >= 0; ) { dig = carry - u[i]; w[i] = lo(dig); carry = signed_hi(dig); } } /* * (u,n) : (v,n) */ static word cmp1(u, v, n) DIGIT *u, *v; word n; { word i; for (i = 0; i < n; i++) if (u[i] != v[i]) return u[i] > v[i] ? 1 : -1; return 0; } /* * (u,n) + k -> (w,n) * * k in 0 .. B-1 * returns carry, 0 or 1 */ static DIGIT addi1(u, k, w, n) DIGIT *u, *w; word k; word n; { uword dig, carry; word i; carry = k; for (i = n; --i >= 0; ) { dig = (uword)u[i] + carry; w[i] = lo(dig); carry = hi(dig); } return carry; } /* * (u,n) - k -> (w,n) * * k in 0 .. B-1 * u must be greater than k */ static novalue subi1(u, k, w, n) DIGIT *u, *w; word k; word n; { uword dig, carry; word i; carry = -k; for (i = n; --i >= 0; ) { dig = (uword)u[i] + carry; w[i] = lo(dig); carry = signed_hi(dig); } } /* * (u,n) * k + c -> (w,n) * * k in 0 .. B-1 * returns carry, 0 .. B-1 */ static DIGIT muli1(u, k, c, w, n) DIGIT *u, *w; word k; int c; word n; { uword dig, carry; word i; carry = c; for (i = n; --i >= 0; ) { dig = (uword)k * u[i] + carry; w[i] = lo(dig); carry = hi(dig); } return carry; } /* * (u,n) / k -> (w,n) * * k in 0 .. B-1 * returns remainder, 0 .. B-1 */ static DIGIT divi1(u, k, w, n) DIGIT *u, *w; word k; word n; { uword dig, remain; word i; remain = 0; for (i = 0; i < n; i++) { dig = dbl(remain, u[i]); w[i] = dig / k; remain = dig % k; } return remain; } /* * ((u,n) << k) + c -> (w,n) * * k in 0 .. NB-1 * c in 0 .. B-1 * returns carry, 0 .. B-1 */ static DIGIT shifti1(u, k, c, w, n) DIGIT *u, c, *w; word k; word n; { uword dig; word i; if (k == 0) { bdcopy(u, w, n); return 0; } for (i = n; --i >= 0; ) { dig = ((uword)u[i] << k) + c; w[i] = lo(dig); c = hi(dig); } return c; } /* * (u,n) : k * * k in 0 .. B-1 */ static word cmpi1(u, k, n) DIGIT *u; word k; word n; { word i; for (i = 0; i < n-1; i++) if (u[i]) return 1; if (u[n - 1] == (DIGIT)k) return 0; return u[n - 1] > (DIGIT)k ? 1 : -1; } static novalue bdzero(dest, l) DIGIT *dest; word l; { word i; for (i = 0; i < l; i++) dest[i] = 0; } static novalue bdcopy(src, dest, l) DIGIT *src, *dest; word l; { word i; for (i = 0; i < l; i++) dest[i] = src[i]; } #else /* LargeInts */ static char x; /* prevent empty module */ #endif /* LargeInts */