ref: 92980154dee84747ca798bafe6e05d87519ab665
parent: 1b0eb3b4437a74231451a95225233fada1039876
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Sat Apr 1 11:46:00 EDT 2023
don't do recursive makefiling
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,8 @@
-/*.[05678qvt]
-/*.o
-/*.out
-/*.a
+*.[05678qvt]
+*.o
+*.out
+*.a
/flisp
-/llt/*.[05678qvt]
-/llt/*.o
-/llt/*.out
-/llt/*.a
/flisp.boot.bak
/flisp.boot.new
boot.h
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,6 @@
BIN=${DESTDIR}${PREFIX}/bin
TARG=flisp
-LLT=llt/libllt.a
CFLAGS?=-O2 -g
CFLAGS+=-Wall -Wextra -Wno-parentheses -std=c99
LDFLAGS?=
@@ -16,6 +15,45 @@
equalhash.o\
table.o\
iostream.o\
+ llt/bitvector-ops.o\
+ llt/bitvector.o\
+ llt/dump.o\
+ llt/hashing.o\
+ llt/htable.o\
+ llt/int2str.o\
+ llt/ios.o\
+ llt/lltinit.o\
+ llt/ptrhash.o\
+ llt/random.o\
+ llt/timefuncs.o\
+ llt/utf8.o\
+ mp/mpadd.o\
+ mp/mpaux.o\
+ mp/mpcmp.o\
+ mp/mpdigdiv.o\
+ mp/mpdiv.o\
+ mp/mpfmt.o\
+ mp/mpleft.o\
+ mp/mplogic.o\
+ mp/mpmul.o\
+ mp/mpright.o\
+ mp/mpsub.o\
+ mp/mptobe.o\
+ mp/mptober.o\
+ mp/mptod.o\
+ mp/mptoi.o\
+ mp/mptoui.o\
+ mp/mptouv.o\
+ mp/mptov.o\
+ mp/mpvecadd.o\
+ mp/mpveccmp.o\
+ mp/mpvecdigmuladd.o\
+ mp/mpvecsub.o\
+ mp/mpvectscmp.o\
+ mp/strtomp.o\
+ mp/u16.o\
+ mp/u32.o\
+ mp/u64.o\
.PHONY: all default test clean
@@ -26,8 +64,8 @@
test: ${TARG}
cd test && ../$(TARG) unittest.lsp
-${TARG}: ${OBJS} ${LLT}
- ${CC} -o $@ ${OBJS} ${LDFLAGS} ${LLT} -lm
+${TARG}: ${OBJS}
+ ${CC} -o $@ ${OBJS} ${LDFLAGS} -lm
.SUFFIXES: .c .o
.c.o:
@@ -42,9 +80,5 @@
builtin_fns.h:
sed -nE 's/^BUILTIN[_]?(\(".*)/BUILTIN_FN\1/gp' *.c >$@
-${LLT}:
- ${MAKE} -C llt CFLAGS="${CFLAGS} -I../posix" CC="${CC}"
-
clean:
- rm -f *.o ${TARG}
- ${MAKE} -C llt clean
+ rm -f ${OBJS} ${TARG}
--- a/llt/Makefile
+++ /dev/null
@@ -1,56 +1,0 @@
-CFLAGS?=-O2 -pipe -g -Wall -falign-functions -Wno-strict-aliasing
-TARG=libllt.a
-
-OBJS=\
- bitvector-ops.o\
- bitvector.o\
- dump.o\
- hashing.o\
- htable.o\
- int2str.o\
- ios.o\
- lltinit.o\
- ptrhash.o\
- random.o\
- timefuncs.o\
- utf8.o\
- \
- mpadd.o\
- mpaux.o\
- mpcmp.o\
- mpdigdiv.o\
- mpdiv.o\
- mpfmt.o\
- mpleft.o\
- mplogic.o\
- mpmul.o\
- mpright.o\
- mpsub.o\
- mptobe.o\
- mptod.o\
- mptoi.o\
- mptoui.o\
- mptouv.o\
- mptov.o\
- mpvecadd.o\
- mpvecdigmuladd.o\
- mpvecsub.o\
- strtomp.o\
- u16.o\
- u32.o\
- u64.o\
- mptober.o\
- mpveccmp.o\
- mpvectscmp.o\
-
-.PHONY: all default clean
-
-all: default
-
-default: ${TARG}
-
-clean:
- rm -f *.o ${TARG}
-
-${TARG}: ${OBJS}
- ${AR} crs ${TARG} ${OBJS}
--- a/llt/mkfile
+++ /dev/null
@@ -1,30 +1,0 @@
-</$objtype/mkfile
-LIB=libllt.$O.a
-
-CFLAGS=$CFLAGS -p -I../plan9 -D__plan9__ -D__${objtype}__
-
-OFILES=\
- bitvector-ops.$O\
- bitvector.$O\
- dump.$O\
- hashing.$O\
- htable.$O\
- int2str.$O\
- ios.$O\
- lltinit.$O\
- ptrhash.$O\
- random.$O\
- timefuncs.$O\
- utf8.$O\
- wcwidth.$O\
-
-HFILES=\
- ../plan9/platform.h\
- bitvector.h\
- htable.h\
- ieee754.h\
- ios.h\
- llt.h\
- utf8.h\
-
-</sys/src/cmd/mklib
--- a/llt/mpadd.c
+++ /dev/null
@@ -1,56 +1,0 @@
-#include "platform.h"
-
-// sum = abs(b1) + abs(b2), i.e., add the magnitudes
-void
-mpmagadd(mpint *b1, mpint *b2, mpint *sum)
-{
- int m, n;
- mpint *t;
-
- sum->flags |= (b1->flags | b2->flags) & MPtimesafe;
-
- // get the sizes right
- if(b2->top > b1->top){
- t = b1;
- b1 = b2;
- b2 = t;
- }
- n = b1->top;
- m = b2->top;
- if(n == 0){
- mpassign(mpzero, sum);
- return;
- }
- if(m == 0){
- mpassign(b1, sum);
- sum->sign = 1;
- return;
- }
- mpbits(sum, (n+1)*Dbits);
- sum->top = n+1;
-
- mpvecadd(b1->p, n, b2->p, m, sum->p);
- sum->sign = 1;
-
- mpnorm(sum);
-}
-
-// sum = b1 + b2
-void
-mpadd(mpint *b1, mpint *b2, mpint *sum)
-{
- int sign;
-
- if(b1->sign != b2->sign){
- assert(((b1->flags | b2->flags | sum->flags) & MPtimesafe) == 0);
- if(b1->sign < 0)
- mpmagsub(b2, b1, sum);
- else
- mpmagsub(b1, b2, sum);
- } else {
- sign = b1->sign;
- mpmagadd(b1, b2, sum);
- if(sum->top != 0)
- sum->sign = sign;
- }
-}
--- a/llt/mpaux.c
+++ /dev/null
@@ -1,201 +1,0 @@
-#include "platform.h"
-
-static mpdigit _mptwodata[1] = { 2 };
-static mpint _mptwo =
-{
- 1, 1, 1,
- _mptwodata,
- MPstatic|MPnorm
-};
-mpint *mptwo = &_mptwo;
-
-static mpdigit _mponedata[1] = { 1 };
-static mpint _mpone =
-{
- 1, 1, 1,
- _mponedata,
- MPstatic|MPnorm
-};
-mpint *mpone = &_mpone;
-
-static mpdigit _mpzerodata[1] = { 0 };
-static mpint _mpzero =
-{
- 1, 1, 0,
- _mpzerodata,
- MPstatic|MPnorm
-};
-mpint *mpzero = &_mpzero;
-
-static int mpmindigits = 33;
-
-// set minimum digit allocation
-void
-mpsetminbits(int n)
-{
- if(n < 0)
- sysfatal("mpsetminbits: n < 0");
- if(n == 0)
- n = 1;
- mpmindigits = DIGITS(n);
-}
-
-// allocate an n bit 0'd number
-mpint*
-mpnew(int n)
-{
- mpint *b;
-
- if(n < 0)
- sysfatal("mpsetminbits: n < 0");
-
- n = DIGITS(n);
- if(n < mpmindigits)
- n = mpmindigits;
- b = calloc(1, sizeof(mpint) + n*Dbytes);
- if(b == nil)
- sysfatal("mpnew: %r");
- b->p = (mpdigit*)&b[1];
- b->size = n;
- b->sign = 1;
- b->flags = MPnorm;
-
- return b;
-}
-
-// guarantee at least n significant bits
-void
-mpbits(mpint *b, int m)
-{
- int n;
-
- n = DIGITS(m);
- if(b->size >= n){
- if(b->top >= n)
- return;
- } else {
- if(b->p == (mpdigit*)&b[1]){
- b->p = (mpdigit*)malloc(n*Dbytes);
- if(b->p == nil)
- sysfatal("mpbits: %r");
- memmove(b->p, &b[1], Dbytes*b->top);
- memset(&b[1], 0, Dbytes*b->size);
- } else {
- b->p = (mpdigit*)realloc(b->p, n*Dbytes);
- if(b->p == nil)
- sysfatal("mpbits: %r");
- }
- b->size = n;
- }
- memset(&b->p[b->top], 0, Dbytes*(n - b->top));
- b->top = n;
- b->flags &= ~MPnorm;
-}
-
-void
-mpfree(mpint *b)
-{
- if(b == nil)
- return;
- if(b->flags & MPstatic)
- sysfatal("freeing mp constant");
- memset(b->p, 0, b->size*Dbytes);
- if(b->p != (mpdigit*)&b[1])
- free(b->p);
- free(b);
-}
-
-mpint*
-mpnorm(mpint *b)
-{
- int i;
-
- if(b->flags & MPtimesafe){
- assert(b->sign == 1);
- b->flags &= ~MPnorm;
- return b;
- }
- for(i = b->top-1; i >= 0; i--)
- if(b->p[i] != 0)
- break;
- b->top = i+1;
- if(b->top == 0)
- b->sign = 1;
- b->flags |= MPnorm;
- return b;
-}
-
-mpint*
-mpcopy(mpint *old)
-{
- mpint *new;
-
- new = mpnew(Dbits*old->size);
- new->sign = old->sign;
- new->top = old->top;
- new->flags = old->flags & ~(MPstatic|MPfield);
- memmove(new->p, old->p, Dbytes*old->top);
- return new;
-}
-
-void
-mpassign(mpint *old, mpint *new)
-{
- if(new == nil || old == new)
- return;
- new->top = 0;
- mpbits(new, Dbits*old->top);
- new->sign = old->sign;
- new->top = old->top;
- new->flags &= ~MPnorm;
- new->flags |= old->flags & ~(MPstatic|MPfield);
- memmove(new->p, old->p, Dbytes*old->top);
-}
-
-// number of significant bits in mantissa
-int
-mpsignif(mpint *n)
-{
- int i, j;
- mpdigit d;
-
- if(n->top == 0)
- return 0;
- for(i = n->top-1; i >= 0; i--){
- d = n->p[i];
- for(j = Dbits-1; j >= 0; j--){
- if(d & (((mpdigit)1)<<j))
- return i*Dbits + j + 1;
- }
- }
- return 0;
-}
-
-// k, where n = 2**k * q for odd q
-int
-mplowbits0(mpint *n)
-{
- int k, bit, digit;
- mpdigit d;
-
- assert(n->flags & MPnorm);
- if(n->top==0)
- return 0;
- k = 0;
- bit = 0;
- digit = 0;
- d = n->p[0];
- for(;;){
- if(d & (1<<bit))
- break;
- k++;
- bit++;
- if(bit==Dbits){
- if(++digit >= n->top)
- return 0;
- d = n->p[digit];
- bit = 0;
- }
- }
- return k;
-}
--- a/llt/mpcmp.c
+++ /dev/null
@@ -1,28 +1,0 @@
-#include "platform.h"
-
-// return neg, 0, pos as abs(b1)-abs(b2) is neg, 0, pos
-int
-mpmagcmp(mpint *b1, mpint *b2)
-{
- int i;
-
- i = b1->flags | b2->flags;
- if(i & MPtimesafe)
- return mpvectscmp(b1->p, b1->top, b2->p, b2->top);
- if(i & MPnorm){
- i = b1->top - b2->top;
- if(i)
- return i;
- }
- return mpveccmp(b1->p, b1->top, b2->p, b2->top);
-}
-
-// return neg, 0, pos as b1-b2 is neg, 0, pos
-int
-mpcmp(mpint *b1, mpint *b2)
-{
- int sign;
-
- sign = (b1->sign - b2->sign) >> 1; // -1, 0, 1
- return sign | (sign&1)-1 & mpmagcmp(b1, b2)*b1->sign;
-}
--- a/llt/mpdigdiv.c
+++ /dev/null
@@ -1,54 +1,0 @@
-#include "platform.h"
-
-//
-// divide two digits by one and return quotient
-//
-void
-mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient)
-{
- mpdigit hi, lo, q, x, y;
- int i;
-
- hi = dividend[1];
- lo = dividend[0];
-
- // return highest digit value if the result >= 2**32
- if(hi >= divisor || divisor == 0){
- divisor = 0;
- *quotient = ~divisor;
- return;
- }
-
- // very common case
- if(~divisor == 0){
- lo += hi;
- if(lo < hi){
- hi++;
- lo++;
- }
- if(lo+1 == 0)
- hi++;
- *quotient = hi;
- return;
- }
-
- // at this point we know that hi < divisor
- // just shift and subtract till we're done
- q = 0;
- x = divisor;
- for(i = Dbits-1; hi > 0 && i >= 0; i--){
- x >>= 1;
- if(x > hi)
- continue;
- y = divisor<<i;
- if(x == hi && y > lo)
- continue;
- if(y > lo)
- hi--;
- lo -= y;
- hi -= x;
- q |= 1U<<i;
- }
- q += lo/divisor;
- *quotient = q;
-}
--- a/llt/mpdiv.c
+++ /dev/null
@@ -1,140 +1,0 @@
-#include "platform.h"
-
-// division ala knuth, seminumerical algorithms, pp 237-238
-// the numbers are stored backwards to what knuth expects so j
-// counts down rather than up.
-
-void
-mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder)
-{
- int j, s, vn, sign, qsign, rsign;
- mpdigit qd, *up, *vp, *qp;
- mpint *u, *v, *t;
-
- assert(quotient != remainder);
- assert(divisor->flags & MPnorm);
-
- // divide bv zero
- if(divisor->top == 0)
- abort();
-
- // division by one or small powers of two
- if(divisor->top == 1 && (divisor->p[0] & divisor->p[0]-1) == 0){
- vlong r = 0;
- if(dividend->top > 0)
- r = (vlong)dividend->sign * (dividend->p[0] & divisor->p[0]-1);
- if(quotient != nil){
- sign = divisor->sign;
- for(s = 0; ((divisor->p[0] >> s) & 1) == 0; s++)
- ;
- mpright(dividend, s, quotient);
- if(sign < 0)
- quotient->sign ^= (-mpmagcmp(quotient, mpzero) >> 31) << 1;
- }
- if(remainder != nil){
- remainder->flags |= dividend->flags & MPtimesafe;
- vtomp(r, remainder);
- }
- return;
- }
- assert((dividend->flags & MPtimesafe) == 0);
-
- // quick check
- if(mpmagcmp(dividend, divisor) < 0){
- if(remainder != nil)
- mpassign(dividend, remainder);
- if(quotient != nil)
- mpassign(mpzero, quotient);
- return;
- }
-
- qsign = divisor->sign * dividend->sign;
- rsign = dividend->sign;
-
- // D1: shift until divisor, v, has hi bit set (needed to make trial
- // divisor accurate)
- qd = divisor->p[divisor->top-1];
- for(s = 0; (qd & mpdighi) == 0; s++)
- qd <<= 1;
- u = mpnew((dividend->top+2)*Dbits + s);
- if(s == 0 && divisor != quotient && divisor != remainder) {
- mpassign(dividend, u);
- v = divisor;
- } else {
- mpleft(dividend, s, u);
- v = mpnew(divisor->top*Dbits);
- mpleft(divisor, s, v);
- }
- up = u->p+u->top-1;
- vp = v->p+v->top-1;
- vn = v->top;
-
- // D1a: make sure high digit of dividend is less than high digit of divisor
- if(*up >= *vp){
- *++up = 0;
- u->top++;
- }
-
- // storage for multiplies
- t = mpnew(4*Dbits);
-
- qp = nil;
- if(quotient != nil){
- mpbits(quotient, (u->top - v->top)*Dbits);
- quotient->top = u->top - v->top;
- qp = quotient->p+quotient->top-1;
- }
-
- // D2, D7: loop on length of dividend
- for(j = u->top; j > vn; j--){
-
- // D3: calculate trial divisor
- mpdigdiv(up-1, *vp, &qd);
-
- // D3a: rule out trial divisors 2 greater than real divisor
- if(vn > 1) for(;;){
- memset(t->p, 0, 3*Dbytes); // mpvecdigmuladd adds to what's there
- mpvecdigmuladd(vp-1, 2, qd, t->p);
- if(mpveccmp(t->p, 3, up-2, 3) > 0)
- qd--;
- else
- break;
- }
-
- // D4: u -= v*qd << j*Dbits
- sign = mpvecdigmulsub(v->p, vn, qd, up-vn);
- if(sign < 0){
-
- // D6: trial divisor was too high, add back borrowed
- // value and decrease divisor
- mpvecadd(up-vn, vn+1, v->p, vn, up-vn);
- qd--;
- }
-
- // D5: save quotient digit
- if(qp != nil)
- *qp-- = qd;
-
- // push top of u down one
- u->top--;
- *up-- = 0;
- }
- if(qp != nil){
- assert((quotient->flags & MPtimesafe) == 0);
- mpnorm(quotient);
- if(quotient->top != 0)
- quotient->sign = qsign;
- }
-
- if(remainder != nil){
- assert((remainder->flags & MPtimesafe) == 0);
- mpright(u, s, remainder); // u is the remainder shifted
- if(remainder->top != 0)
- remainder->sign = rsign;
- }
-
- mpfree(t);
- mpfree(u);
- if(v != divisor)
- mpfree(v);
-}
--- a/llt/mpfmt.c
+++ /dev/null
@@ -1,207 +1,0 @@
-#include "platform.h"
-
-static int
-toencx(mpint *b, char *buf, int len, int (*enc)(char*, int, uchar*, int))
-{
- uchar *p;
- int n, rv;
-
- p = nil;
- n = mptobe(b, nil, 0, &p);
- if(n < 0)
- return -1;
- rv = (*enc)(buf, len, p, n);
- free(p);
- return rv;
-}
-
-static int
-topow2(mpint *b, char *buf, int len, int s)
-{
- mpdigit *p, x;
- int i, j, sn;
- char *out, *eout;
-
- if(len < 1)
- return -1;
-
- sn = 1<<s;
- out = buf;
- eout = buf+len;
- for(p = &b->p[b->top-1]; p >= b->p; p--){
- x = *p;
- for(i = Dbits-s; i >= 0; i -= s){
- j = x >> i & sn - 1;
- if(j != 0 || out != buf){
- if(out >= eout)
- return -1;
- *out++ = enc16chr(j);
- }
- }
- }
- if(out == buf)
- *out++ = '0';
- if(out >= eout)
- return -1;
- *out = 0;
- return 0;
-}
-
-static char*
-modbillion(int rem, ulong r, char *out, char *buf)
-{
- ulong rr;
- int i;
-
- for(i = 0; i < 9; i++){
- rr = r%10;
- r /= 10;
- if(out <= buf)
- return nil;
- *--out = '0' + rr;
- if(rem == 0 && r == 0)
- break;
- }
- return out;
-}
-
-static int
-to10(mpint *b, char *buf, int len)
-{
- mpint *d, *r, *billion;
- char *out;
-
- if(len < 1)
- return -1;
-
- d = mpcopy(b);
- d->flags &= ~MPtimesafe;
- mpnorm(d);
- r = mpnew(0);
- billion = uitomp(1000000000, nil);
- out = buf+len;
- *--out = 0;
- do {
- mpdiv(d, billion, d, r);
- out = modbillion(d->top, r->p[0], out, buf);
- if(out == nil)
- break;
- } while(d->top != 0);
- mpfree(d);
- mpfree(r);
- mpfree(billion);
-
- if(out == nil)
- return -1;
- len -= out-buf;
- if(out != buf)
- memmove(buf, out, len);
- return 0;
-}
-
-static int
-to8(mpint *b, char *buf, int len)
-{
- mpdigit x, y;
- char *out;
- int i, j;
-
- if(len < 2)
- return -1;
-
- out = buf+len;
- *--out = 0;
-
- i = j = 0;
- x = y = 0;
- while(j < b->top){
- y = b->p[j++];
- if(i > 0)
- x |= y << i;
- else
- x = y;
- i += Dbits;
- while(i >= 3){
-Digout: i -= 3;
- if(out > buf)
- out--;
- else if(x != 0)
- return -1;
- *out = '0' + (x & 7);
- x = y >> (Dbits-i);
- }
- }
- if(i > 0)
- goto Digout;
-
- while(*out == '0') out++;
- if(*out == '\0')
- *--out = '0';
-
- len -= out-buf;
- if(out != buf)
- memmove(buf, out, len);
- return 0;
-}
-
-char*
-mptoa(mpint *b, int base, char *buf, int len)
-{
- char *out;
- int rv, alloced;
-
- if(base == 0)
- base = 16; /* default */
- alloced = 0;
- if(buf == nil){
- /* rv <= log₂(base) */
- for(rv=1; (base >> rv) > 1; rv++)
- ;
- len = 10 + (b->top*Dbits / rv);
- buf = malloc(len);
- if(buf == nil)
- return nil;
- alloced = 1;
- }
-
- if(len < 2)
- return nil;
-
- out = buf;
- if(b->sign < 0){
- *out++ = '-';
- len--;
- }
- switch(base){
- case 64:
- rv = toencx(b, out, len, enc64);
- break;
- case 32:
- rv = toencx(b, out, len, enc32);
- break;
- case 16:
- rv = topow2(b, out, len, 4);
- break;
- case 10:
- rv = to10(b, out, len);
- break;
- case 8:
- rv = to8(b, out, len);
- break;
- case 4:
- rv = topow2(b, out, len, 2);
- break;
- case 2:
- rv = topow2(b, out, len, 1);
- break;
- default:
- abort();
- return nil;
- }
- if(rv < 0){
- if(alloced)
- free(buf);
- return nil;
- }
- return buf;
-}
--- a/llt/mpleft.c
+++ /dev/null
@@ -1,49 +1,0 @@
-#include "platform.h"
-
-// res = b << shift
-void
-mpleft(mpint *b, int shift, mpint *res)
-{
- int d, l, r, i, otop;
- mpdigit this, last;
-
- res->sign = b->sign;
- if(b->top==0){
- res->top = 0;
- return;
- }
-
- // a zero or negative left shift is a right shift
- if(shift <= 0){
- mpright(b, -shift, res);
- return;
- }
-
- // b and res may be the same so remember the old top
- otop = b->top;
-
- // shift
- mpbits(res, otop*Dbits + shift); // overkill
- res->top = DIGITS(otop*Dbits + shift);
- d = shift/Dbits;
- l = shift - d*Dbits;
- r = Dbits - l;
-
- if(l == 0){
- for(i = otop-1; i >= 0; i--)
- res->p[i+d] = b->p[i];
- } else {
- last = 0;
- for(i = otop-1; i >= 0; i--) {
- this = b->p[i];
- res->p[i+d+1] = (last<<l) | (this>>r);
- last = this;
- }
- res->p[d] = last<<l;
- }
- for(i = 0; i < d; i++)
- res->p[i] = 0;
-
- res->flags |= b->flags & MPtimesafe;
- mpnorm(res);
-}
--- a/llt/mplogic.c
+++ /dev/null
@@ -1,210 +1,0 @@
-#include "platform.h"
-
-/*
- mplogic calculates b1|b2 subject to the
- following flag bits (fl)
-
- bit 0: subtract 1 from b1
- bit 1: invert b1
- bit 2: subtract 1 from b2
- bit 3: invert b2
- bit 4: add 1 to output
- bit 5: invert output
-
- it inverts appropriate bits automatically
- depending on the signs of the inputs
-*/
-
-static void
-mplogic(mpint *b1, mpint *b2, mpint *sum, int fl)
-{
- mpint *t;
- mpdigit *dp1, *dp2, *dpo, d1, d2, d;
- int c1, c2, co;
- int i;
-
- assert(((b1->flags | b2->flags | sum->flags) & MPtimesafe) == 0);
- if(b1->sign < 0) fl ^= 0x03;
- if(b2->sign < 0) fl ^= 0x0c;
- sum->sign = (int)(((fl|fl>>2)^fl>>4)<<30)>>31|1;
- if(sum->sign < 0) fl ^= 0x30;
- if(b2->top > b1->top){
- t = b1;
- b1 = b2;
- b2 = t;
- fl = fl >> 2 & 0x03 | fl << 2 & 0x0c | fl & 0x30;
- }
- mpbits(sum, b1->top*Dbits+1);
- dp1 = b1->p;
- dp2 = b2->p;
- dpo = sum->p;
- c1 = fl & 1;
- c2 = fl >> 2 & 1;
- co = fl >> 4 & 1;
- for(i = 0; i < b1->top; i++){
- d1 = dp1[i] - c1;
- if(i < b2->top)
- d2 = dp2[i] - c2;
- else
- d2 = 0;
- if(d1 != (mpdigit)-1) c1 = 0;
- if(d2 != (mpdigit)-1) c2 = 0;
- if((fl & 2) != 0) d1 ^= -1;
- if((fl & 8) != 0) d2 ^= -1;
- d = d1 | d2;
- if((fl & 32) != 0) d ^= -1;
- d += co;
- if(d != 0) co = 0;
- dpo[i] = d;
- }
- sum->top = i;
- if(co)
- dpo[sum->top++] = co;
- mpnorm(sum);
-}
-
-void
-mpor(mpint *b1, mpint *b2, mpint *sum)
-{
- mplogic(b1, b2, sum, 0);
-}
-
-void
-mpand(mpint *b1, mpint *b2, mpint *sum)
-{
- mplogic(b1, b2, sum, 0x2a);
-}
-
-void
-mpbic(mpint *b1, mpint *b2, mpint *sum)
-{
- mplogic(b1, b2, sum, 0x22);
-}
-
-void
-mpnot(mpint *b, mpint *r)
-{
- mpadd(b, mpone, r);
- if(r->top != 0)
- r->sign ^= -2;
-}
-
-void
-mpxor(mpint *b1, mpint *b2, mpint *sum)
-{
- mpint *t;
- mpdigit *dp1, *dp2, *dpo, d1, d2, d;
- int c1, c2, co;
- int i, fl;
-
- assert(((b1->flags | b2->flags | sum->flags) & MPtimesafe) == 0);
- if(b2->top > b1->top){
- t = b1;
- b1 = b2;
- b2 = t;
- }
- fl = (b1->sign & 10) ^ (b2->sign & 12);
- sum->sign = (int)(fl << 28) >> 31 | 1;
- mpbits(sum, b1->top*Dbits+1);
- dp1 = b1->p;
- dp2 = b2->p;
- dpo = sum->p;
- c1 = fl >> 1 & 1;
- c2 = fl >> 2 & 1;
- co = fl >> 3 & 1;
- for(i = 0; i < b1->top; i++){
- d1 = dp1[i] - c1;
- if(i < b2->top)
- d2 = dp2[i] - c2;
- else
- d2 = 0;
- if(d1 != (mpdigit)-1) c1 = 0;
- if(d2 != (mpdigit)-1) c2 = 0;
- d = d1 ^ d2;
- d += co;
- if(d != 0) co = 0;
- dpo[i] = d;
- }
- sum->top = i;
- if(co)
- dpo[sum->top++] = co;
- mpnorm(sum);
-}
-
-void
-mptrunc(mpint *b, int n, mpint *r)
-{
- int d, m, i, c;
-
- assert(((b->flags | r->flags) & MPtimesafe) == 0);
- mpbits(r, n);
- r->top = DIGITS(n);
- d = n / Dbits;
- m = n % Dbits;
- if(b->sign == -1){
- c = 1;
- for(i = 0; i < r->top; i++){
- if(i < b->top)
- r->p[i] = ~(b->p[i] - c);
- else
- r->p[i] = -1;
- if(r->p[i] != 0)
- c = 0;
- }
- if(m != 0)
- r->p[d] &= (1<<m) - 1;
- }else if(b->sign == 1){
- if(d >= b->top){
- mpassign(b, r);
- mpnorm(r);
- return;
- }
- if(b != r)
- for(i = 0; i < d; i++)
- r->p[i] = b->p[i];
- if(m != 0)
- r->p[d] = b->p[d] & (1<<m)-1;
- }
- r->sign = 1;
- mpnorm(r);
-}
-
-void
-mpxtend(mpint *b, int n, mpint *r)
-{
- int d, m, c, i;
-
- d = (n - 1) / Dbits;
- m = (n - 1) % Dbits;
- if(d >= b->top){
- mpassign(b, r);
- return;
- }
- mptrunc(b, n, r);
- mpbits(r, n);
- if((r->p[d] & 1<<m) == 0){
- mpnorm(r);
- return;
- }
- r->p[d] |= -(1<<m);
- r->sign = -1;
- c = 1;
- for(i = 0; i < r->top; i++){
- r->p[i] = ~(r->p[i] - c);
- if(r->p[i] != 0)
- c = 0;
- }
- mpnorm(r);
-}
-
-void
-mpasr(mpint *b, int n, mpint *r)
-{
- if(b->sign > 0 || n <= 0){
- mpright(b, n, r);
- return;
- }
- mpadd(b, mpone, r);
- mpright(r, n, r);
- mpsub(r, mpone, r);
-}
--- a/llt/mpmul.c
+++ /dev/null
@@ -1,174 +1,0 @@
-#include "platform.h"
-
-//
-// from knuth's 1969 seminumberical algorithms, pp 233-235 and pp 258-260
-//
-// mpvecmul is an assembly language routine that performs the inner
-// loop.
-//
-// the karatsuba trade off is set empiricly by measuring the algs on
-// a 400 MHz Pentium II.
-//
-
-// karatsuba like (see knuth pg 258)
-// prereq: p is already zeroed
-static void
-mpkaratsuba(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
-{
- mpdigit *t, *u0, *u1, *v0, *v1, *u0v0, *u1v1, *res, *diffprod;
- int u0len, u1len, v0len, v1len, reslen;
- int sign, n;
-
- // divide each piece in half
- n = alen/2;
- if(alen&1)
- n++;
- u0len = n;
- u1len = alen-n;
- if(blen > n){
- v0len = n;
- v1len = blen-n;
- } else {
- v0len = blen;
- v1len = 0;
- }
- u0 = a;
- u1 = a + u0len;
- v0 = b;
- v1 = b + v0len;
-
- // room for the partial products
- t = calloc(1, Dbytes*5*(2*n+1));
- if(t == nil)
- sysfatal("mpkaratsuba: %r");
- u0v0 = t;
- u1v1 = t + (2*n+1);
- diffprod = t + 2*(2*n+1);
- res = t + 3*(2*n+1);
- reslen = 4*n+1;
-
- // t[0] = (u1-u0)
- sign = 1;
- if(mpveccmp(u1, u1len, u0, u0len) < 0){
- sign = -1;
- mpvecsub(u0, u0len, u1, u1len, u0v0);
- } else
- mpvecsub(u1, u1len, u0, u1len, u0v0);
-
- // t[1] = (v0-v1)
- if(mpveccmp(v0, v0len, v1, v1len) < 0){
- sign *= -1;
- mpvecsub(v1, v1len, v0, v1len, u1v1);
- } else
- mpvecsub(v0, v0len, v1, v1len, u1v1);
-
- // t[4:5] = (u1-u0)*(v0-v1)
- mpvecmul(u0v0, u0len, u1v1, v0len, diffprod);
-
- // t[0:1] = u1*v1
- memset(t, 0, 2*(2*n+1)*Dbytes);
- if(v1len > 0)
- mpvecmul(u1, u1len, v1, v1len, u1v1);
-
- // t[2:3] = u0v0
- mpvecmul(u0, u0len, v0, v0len, u0v0);
-
- // res = u0*v0<<n + u0*v0
- mpvecadd(res, reslen, u0v0, u0len+v0len, res);
- mpvecadd(res+n, reslen-n, u0v0, u0len+v0len, res+n);
-
- // res += u1*v1<<n + u1*v1<<2*n
- if(v1len > 0){
- mpvecadd(res+n, reslen-n, u1v1, u1len+v1len, res+n);
- mpvecadd(res+2*n, reslen-2*n, u1v1, u1len+v1len, res+2*n);
- }
-
- // res += (u1-u0)*(v0-v1)<<n
- if(sign < 0)
- mpvecsub(res+n, reslen-n, diffprod, u0len+v0len, res+n);
- else
- mpvecadd(res+n, reslen-n, diffprod, u0len+v0len, res+n);
- memmove(p, res, (alen+blen)*Dbytes);
-
- free(t);
-}
-
-#define KARATSUBAMIN 32
-
-void
-mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
-{
- int i;
- mpdigit d;
- mpdigit *t;
-
- // both mpvecdigmuladd and karatsuba are fastest when a is the longer vector
- if(alen < blen){
- i = alen;
- alen = blen;
- blen = i;
- t = a;
- a = b;
- b = t;
- }
-
- if(alen >= KARATSUBAMIN && blen > 1){
- // O(n^1.585)
- mpkaratsuba(a, alen, b, blen, p);
- } else {
- // O(n^2)
- for(i = 0; i < blen; i++){
- d = b[i];
- if(d != 0)
- mpvecdigmuladd(a, alen, d, &p[i]);
- }
- }
-}
-
-void
-mpvectsmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
-{
- int i;
- mpdigit *t;
-
- if(alen < blen){
- i = alen;
- alen = blen;
- blen = i;
- t = a;
- a = b;
- b = t;
- }
- if(blen == 0)
- return;
- for(i = 0; i < blen; i++)
- mpvecdigmuladd(a, alen, b[i], &p[i]);
-}
-
-void
-mpmul(mpint *b1, mpint *b2, mpint *prod)
-{
- mpint *oprod;
-
- oprod = prod;
- if(prod == b1 || prod == b2){
- prod = mpnew(0);
- prod->flags = oprod->flags;
- }
- prod->flags |= (b1->flags | b2->flags) & MPtimesafe;
-
- prod->top = 0;
- mpbits(prod, (b1->top+b2->top+1)*Dbits);
- if(prod->flags & MPtimesafe)
- mpvectsmul(b1->p, b1->top, b2->p, b2->top, prod->p);
- else
- mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p);
- prod->top = b1->top+b2->top+1;
- prod->sign = b1->sign*b2->sign;
- mpnorm(prod);
-
- if(oprod != prod){
- mpassign(prod, oprod);
- mpfree(prod);
- }
-}
--- a/llt/mpright.c
+++ /dev/null
@@ -1,55 +1,0 @@
-#include "platform.h"
-
-// res = b >> shift
-void
-mpright(mpint *b, int shift, mpint *res)
-{
- int d, l, r, i;
- mpdigit this, last;
-
- res->sign = b->sign;
- if(b->top==0){
- res->top = 0;
- return;
- }
-
- // a negative right shift is a left shift
- if(shift < 0){
- mpleft(b, -shift, res);
- return;
- }
-
- if(res != b)
- mpbits(res, b->top*Dbits - shift);
- else if(shift == 0)
- return;
-
- d = shift/Dbits;
- r = shift - d*Dbits;
- l = Dbits - r;
-
- // shift all the bits out == zero
- if(d>=b->top){
- res->sign = 1;
- res->top = 0;
- return;
- }
-
- // special case digit shifts
- if(r == 0){
- for(i = 0; i < b->top-d; i++)
- res->p[i] = b->p[i+d];
- } else {
- last = b->p[d];
- for(i = 0; i < b->top-d-1; i++){
- this = b->p[i+d+1];
- res->p[i] = (this<<l) | (last>>r);
- last = this;
- }
- res->p[i++] = last>>r;
- }
-
- res->top = i;
- res->flags |= b->flags & MPtimesafe;
- mpnorm(res);
-}
--- a/llt/mpsub.c
+++ /dev/null
@@ -1,54 +1,0 @@
-#include "platform.h"
-
-// diff = abs(b1) - abs(b2), i.e., subtract the magnitudes
-void
-mpmagsub(mpint *b1, mpint *b2, mpint *diff)
-{
- int n, m, sign;
- mpint *t;
-
- // get the sizes right
- if(mpmagcmp(b1, b2) < 0){
- assert(((b1->flags | b2->flags | diff->flags) & MPtimesafe) == 0);
- sign = -1;
- t = b1;
- b1 = b2;
- b2 = t;
- } else {
- diff->flags |= (b1->flags | b2->flags) & MPtimesafe;
- sign = 1;
- }
- n = b1->top;
- m = b2->top;
- if(m == 0){
- mpassign(b1, diff);
- diff->sign = sign;
- return;
- }
- mpbits(diff, n*Dbits);
-
- mpvecsub(b1->p, n, b2->p, m, diff->p);
- diff->sign = sign;
- diff->top = n;
- mpnorm(diff);
-}
-
-// diff = b1 - b2
-void
-mpsub(mpint *b1, mpint *b2, mpint *diff)
-{
- int sign;
-
- if(b1->sign != b2->sign){
- assert(((b1->flags | b2->flags | diff->flags) & MPtimesafe) == 0);
- sign = b1->sign;
- mpmagadd(b1, b2, diff);
- diff->sign = sign;
- return;
- }
-
- sign = b1->sign;
- mpmagsub(b1, b2, diff);
- if(diff->top != 0)
- diff->sign *= sign;
-}
--- a/llt/mptobe.c
+++ /dev/null
@@ -1,29 +1,0 @@
-#include "platform.h"
-
-// convert an mpint into a big endian byte array (most significant byte first; left adjusted)
-// return number of bytes converted
-// if p == nil, allocate and result array
-int
-mptobe(mpint *b, uchar *p, uint n, uchar **pp)
-{
- uint m;
-
- m = (mpsignif(b)+7)/8;
- if(m == 0)
- m++;
- if(p == nil){
- n = m;
- p = malloc(n);
- if(p == nil)
- sysfatal("mptobe: %r");
- } else {
- if(n < m)
- return -1;
- if(n > m)
- memset(p+m, 0, n-m);
- }
- if(pp != nil)
- *pp = p;
- mptober(b, p, m);
- return m;
-}
--- a/llt/mptober.c
+++ /dev/null
@@ -1,32 +1,0 @@
-#include "platform.h"
-
-void
-mptober(mpint *b, uchar *p, int n)
-{
- int i, j, m;
- mpdigit x;
-
- memset(p, 0, n);
-
- p += n;
- m = b->top*Dbytes;
- if(m < n)
- n = m;
-
- i = 0;
- while(n >= Dbytes){
- n -= Dbytes;
- x = b->p[i++];
- for(j = 0; j < Dbytes; j++){
- *--p = x;
- x >>= 8;
- }
- }
- if(n > 0){
- x = b->p[i];
- for(j = 0; j < n; j++){
- *--p = x;
- x >>= 8;
- }
- }
-}
--- a/llt/mptod.c
+++ /dev/null
@@ -1,83 +1,0 @@
-#include "platform.h"
-
-extern double D_PINF, D_NINF;
-
-double
-mptod(mpint *a)
-{
- u64int v;
- mpdigit w, r;
- int sf, i, n, m, s;
- FPdbleword x;
-
- if(a->top == 0) return 0.0;
- sf = mpsignif(a);
- if(sf > 1024) return a->sign < 0 ? D_NINF : D_PINF;
- i = a->top - 1;
- v = a->p[i];
- n = sf & Dbits - 1;
- n |= n - 1 & Dbits;
- r = 0;
- if(n > 54){
- s = n - 54;
- r = v & (1<<s) - 1;
- v >>= s;
- }
- while(n < 54){
- if(--i < 0)
- w = 0;
- else
- w = a->p[i];
- m = 54 - n;
- if(m > Dbits) m = Dbits;
- s = Dbits - m & Dbits - 1;
- v = v << m | w >> s;
- r = w & (1<<s) - 1;
- n += m;
- }
- if((v & 3) == 1){
- while(--i >= 0)
- r |= a->p[i];
- if(r != 0)
- v++;
- }else
- v++;
- v >>= 1;
- while((v >> 53) != 0){
- v >>= 1;
- if(++sf > 1024)
- return a->sign < 0 ? D_NINF : D_PINF;
- }
- x.lo = v;
- x.hi = (u32int)(v >> 32) & (1<<20) - 1 | (sf + 1022) << 20 | a->sign & 1<<31;
- return x.x;
-}
-
-mpint *
-dtomp(double d, mpint *a)
-{
- FPdbleword x;
- uvlong v;
- int e;
-
- if(a == nil)
- a = mpnew(0);
- x.x = d;
- e = x.hi >> 20 & 2047;
- assert(e != 2047);
- if(e < 1022){
- mpassign(mpzero, a);
- return a;
- }
- v = x.lo | (uvlong)(x.hi & (1<<20) - 1) << 32 | 1ULL<<52;
- if(e < 1075){
- v += (1ULL<<(1074 - e)) - (~v >> (1075 - e) & 1);
- v >>= 1075 - e;
- }
- uvtomp(v, a);
- if(e > 1075)
- mpleft(a, e - 1075, a);
- if((int)x.hi < 0)
- a->sign = -1;
- return a;
-}
--- a/llt/mptoi.c
+++ /dev/null
@@ -1,41 +1,0 @@
-#include "platform.h"
-
-/*
- * this code assumes that mpdigit is at least as
- * big as an int.
- */
-
-mpint*
-itomp(int i, mpint *b)
-{
- if(b == nil){
- b = mpnew(0);
- }
- b->sign = (i >> (sizeof(i)*8 - 1)) | 1;
- i *= b->sign;
- *b->p = i;
- b->top = 1;
- return mpnorm(b);
-}
-
-int
-mptoi(mpint *b)
-{
- uint x;
-
- if(b->top==0)
- return 0;
- x = *b->p;
- if(b->sign > 0){
- if(b->top > 1 || (x > MAXINT))
- x = (int)MAXINT;
- else
- x = (int)x;
- } else {
- if(b->top > 1 || x > MAXINT+1)
- x = (int)MININT;
- else
- x = -(int)x;
- }
- return x;
-}
--- a/llt/mptoui.c
+++ /dev/null
@@ -1,31 +1,0 @@
-#include "platform.h"
-
-/*
- * this code assumes that mpdigit is at least as
- * big as an int.
- */
-
-mpint*
-uitomp(uint i, mpint *b)
-{
- if(b == nil){
- b = mpnew(0);
- }
- *b->p = i;
- b->top = 1;
- b->sign = 1;
- return mpnorm(b);
-}
-
-uint
-mptoui(mpint *b)
-{
- uint x;
-
- x = *b->p;
- if(b->sign < 0)
- x = 0;
- else if(b->top > 1 || (sizeof(mpdigit) > sizeof(uint) && x > MAXUINT))
- x = MAXUINT;
- return x;
-}
--- a/llt/mptouv.c
+++ /dev/null
@@ -1,44 +1,0 @@
-#include "platform.h"
-
-#define VLDIGITS (int)(sizeof(vlong)/sizeof(mpdigit))
-
-/*
- * this code assumes that a vlong is an integral number of
- * mpdigits long.
- */
-mpint*
-uvtomp(uvlong v, mpint *b)
-{
- int s;
-
- if(b == nil){
- b = mpnew(VLDIGITS*Dbits);
- }else
- mpbits(b, VLDIGITS*Dbits);
- b->sign = 1;
- for(s = 0; s < VLDIGITS; s++){
- b->p[s] = v;
- v >>= sizeof(mpdigit)*8;
- }
- b->top = s;
- return mpnorm(b);
-}
-
-uvlong
-mptouv(mpint *b)
-{
- uvlong v;
- int s;
-
- if(b->top == 0 || b->sign < 0)
- return 0LL;
-
- if(b->top > VLDIGITS)
- return -1LL;
-
- v = 0ULL;
- for(s = 0; s < b->top; s++)
- v |= (uvlong)b->p[s]<<(s*sizeof(mpdigit)*8);
-
- return v;
-}
--- a/llt/mptov.c
+++ /dev/null
@@ -1,60 +1,0 @@
-#include "platform.h"
-
-#define VLDIGITS (int)(sizeof(vlong)/sizeof(mpdigit))
-
-/*
- * this code assumes that a vlong is an integral number of
- * mpdigits long.
- */
-mpint*
-vtomp(vlong v, mpint *b)
-{
- int s;
- uvlong uv;
-
- if(b == nil){
- b = mpnew(VLDIGITS*Dbits);
- }else
- mpbits(b, VLDIGITS*Dbits);
- b->sign = (v >> (sizeof(v)*8 - 1)) | 1;
- uv = v * b->sign;
- for(s = 0; s < VLDIGITS; s++){
- b->p[s] = uv;
- uv >>= sizeof(mpdigit)*8;
- }
- b->top = s;
- return mpnorm(b);
-}
-
-vlong
-mptov(mpint *b)
-{
- uvlong v;
- int s;
-
- if(b->top == 0)
- return 0LL;
-
- if(b->top > VLDIGITS){
- if(b->sign > 0)
- return (vlong)MAXVLONG;
- else
- return (vlong)MINVLONG;
- }
-
- v = 0ULL;
- for(s = 0; s < b->top; s++)
- v |= (uvlong)b->p[s]<<(s*sizeof(mpdigit)*8);
-
- if(b->sign > 0){
- if(v > MAXVLONG)
- v = MAXVLONG;
- } else {
- if(v > MINVLONG)
- v = MINVLONG;
- else
- v = -(vlong)v;
- }
-
- return (vlong)v;
-}
--- a/llt/mpvecadd.c
+++ /dev/null
@@ -1,34 +1,0 @@
-#include "platform.h"
-
-// prereq: alen >= blen, sum has at least blen+1 digits
-void
-mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
-{
- int i;
- uint carry;
- mpdigit x, y;
-
- carry = 0;
- for(i = 0; i < blen; i++){
- x = *a++;
- y = *b++;
- x += carry;
- if(x < carry)
- carry = 1;
- else
- carry = 0;
- x += y;
- if(x < y)
- carry++;
- *sum++ = x;
- }
- for(; i < alen; i++){
- x = *a++ + carry;
- if(x < carry)
- carry = 1;
- else
- carry = 0;
- *sum++ = x;
- }
- *sum = carry;
-}
--- a/llt/mpveccmp.c
+++ /dev/null
@@ -1,25 +1,0 @@
-#include "platform.h"
-
-int
-mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen)
-{
- mpdigit x;
-
- while(alen > blen)
- if(a[--alen] != 0)
- return 1;
- while(blen > alen)
- if(b[--blen] != 0)
- return -1;
- while(alen > 0){
- --alen;
- x = a[alen] - b[alen];
- if(x == 0)
- continue;
- if(x > a[alen])
- return -1;
- else
- return 1;
- }
- return 0;
-}
--- a/llt/mpvecdigmuladd.c
+++ /dev/null
@@ -1,101 +1,0 @@
-#include "platform.h"
-
-#define LO(x) ((x) & ((1<<(Dbits/2))-1))
-#define HI(x) ((x) >> (Dbits/2))
-
-static void
-mpdigmul(mpdigit a, mpdigit b, mpdigit *p)
-{
- mpdigit x, ah, al, bh, bl, p1, p2, p3, p4;
- int carry;
-
- // half digits
- ah = HI(a);
- al = LO(a);
- bh = HI(b);
- bl = LO(b);
-
- // partial products
- p1 = ah*bl;
- p2 = bh*al;
- p3 = bl*al;
- p4 = ah*bh;
-
- // p = ((p1+p2)<<(Dbits/2)) + (p4<<Dbits) + p3
- carry = 0;
- x = p1<<(Dbits/2);
- p3 += x;
- if(p3 < x)
- carry++;
- x = p2<<(Dbits/2);
- p3 += x;
- if(p3 < x)
- carry++;
- p4 += carry + HI(p1) + HI(p2); // can't carry out of the high digit
- p[0] = p3;
- p[1] = p4;
-}
-
-// prereq: p must have room for n+1 digits
-void
-mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
-{
- int i;
- mpdigit carry, x, y, part[2];
-
- carry = 0;
- part[1] = 0;
- for(i = 0; i < n; i++){
- x = part[1] + carry;
- if(x < carry)
- carry = 1;
- else
- carry = 0;
- y = *p;
- mpdigmul(*b++, m, part);
- x += part[0];
- if(x < part[0])
- carry++;
- x += y;
- if(x < y)
- carry++;
- *p++ = x;
- }
- *p = part[1] + carry;
-}
-
-// prereq: p must have room for n+1 digits
-int
-mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
-{
- int i;
- mpdigit x, y, part[2], borrow;
-
- borrow = 0;
- part[1] = 0;
- for(i = 0; i < n; i++){
- x = *p;
- y = x - borrow;
- if(y > x)
- borrow = 1;
- else
- borrow = 0;
- x = part[1];
- mpdigmul(*b++, m, part);
- x += part[0];
- if(x < part[0])
- borrow++;
- x = y - x;
- if(x > y)
- borrow++;
- *p++ = x;
- }
-
- x = *p;
- y = x - borrow - part[1];
- *p = y;
- if(y > x)
- return -1;
- else
- return 1;
-}
--- a/llt/mpvecsub.c
+++ /dev/null
@@ -1,32 +1,0 @@
-#include "platform.h"
-
-// prereq: a >= b, alen >= blen, diff has at least alen digits
-void
-mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
-{
- int i, borrow;
- mpdigit x, y;
-
- borrow = 0;
- for(i = 0; i < blen; i++){
- x = *a++;
- y = *b++;
- y += borrow;
- if(y < (mpdigit)borrow)
- borrow = 1;
- else
- borrow = 0;
- if(x < y)
- borrow++;
- *diff++ = x - y;
- }
- for(; i < alen; i++){
- x = *a++;
- y = x - borrow;
- if(y > x)
- borrow = 1;
- else
- borrow = 0;
- *diff++ = y;
- }
-}
--- a/llt/mpvectscmp.c
+++ /dev/null
@@ -1,32 +1,0 @@
-#include "platform.h"
-
-int
-mpvectscmp(mpdigit *a, int alen, mpdigit *b, int blen)
-{
- mpdigit x, y, z, v;
- int m, p;
-
- if(alen > blen){
- v = 0;
- while(alen > blen)
- v |= a[--alen];
- m = p = (-v^v|v)>>(Dbits-1);
- } else if(blen > alen){
- v = 0;
- while(blen > alen)
- v |= b[--blen];
- m = (-v^v|v)>>(Dbits-1);
- p = m^1;
- } else
- m = p = 0;
- while(alen-- > 0){
- x = a[alen];
- y = b[alen];
- z = x - y;
- x = ~x;
- v = ((-z^z|z)>>(Dbits-1)) & ~m;
- p = ((~(x&y|x&z|y&z)>>(Dbits-1)) & v) | (p & ~v);
- m |= v;
- }
- return (p-m) | m;
-}
--- a/llt/strtomp.c
+++ /dev/null
@@ -1,174 +1,0 @@
-#include "platform.h"
-
-static char*
-frompow2(char *a, mpint *b, int s)
-{
- char *p, *next;
- mpdigit x;
- int i;
-
- i = 1<<s;
- for(p = a; (dec16chr(*p) & 255) < i; p++)
- ;
-
- mpbits(b, (p-a)*s);
- b->top = 0;
- next = p;
-
- while(p > a){
- x = 0;
- for(i = 0; i < Dbits; i += s){
- if(p <= a)
- break;
- x |= dec16chr(*--p)<<i;
- }
- b->p[b->top++] = x;
- }
- return next;
-}
-
-static char*
-from8(char *a, mpint *b)
-{
- char *p, *next;
- mpdigit x, y;
- int i;
-
- for(p = a; ((*p - '0') & 255) < 8; p++)
- ;
-
- mpbits(b, (p-a)*3);
- b->top = 0;
- next = p;
-
- i = 0;
- x = y = 0;
- while(p > a){
- y = *--p - '0';
- x |= y << i;
- i += 3;
- if(i >= Dbits){
-Digout:
- i -= Dbits;
- b->p[b->top++] = x;
- x = y >> (3-i);
- }
- }
- if(i > 0)
- goto Digout;
-
- return next;
-}
-
-static ulong mppow10[] = {
- 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
-};
-
-static char*
-from10(char *a, mpint *b)
-{
- ulong x, y;
- mpint *pow, *r;
- int i;
-
- pow = mpnew(0);
- r = mpnew(0);
-
- b->top = 0;
- for(;;){
- // do a billion at a time in native arithmetic
- x = 0;
- for(i = 0; i < 9; i++){
- y = *a - '0';
- if(y > 9)
- break;
- a++;
- x *= 10;
- x += y;
- }
- if(i == 0)
- break;
-
- // accumulate into mpint
- uitomp(mppow10[i], pow);
- uitomp(x, r);
- mpmul(b, pow, b);
- mpadd(b, r, b);
- if(i < 9)
- break;
- }
- mpfree(pow);
- mpfree(r);
- return a;
-}
-
-mpint*
-strtomp(char *a, char **pp, int base, mpint *b)
-{
- int sign;
- char *e;
-
- if(b == nil){
- b = mpnew(0);
- }
-
- while(*a==' ' || *a=='\t')
- a++;
-
- sign = 1;
- for(;; a++){
- switch(*a){
- case '-':
- sign *= -1;
- continue;
- }
- break;
- }
-
- if(base == 0){
- base = 10;
- if(a[0] == '0'){
- if(a[1] == 'x' || a[1] == 'X') {
- a += 2;
- base = 16;
- } else if(a[1] == 'b' || a[1] == 'B') {
- a += 2;
- base = 2;
- } else if(a[1] >= '0' && a[1] <= '7') {
- a++;
- base = 8;
- }
- }
- }
-
- switch(base){
- case 2:
- e = frompow2(a, b, 1);
- break;
- case 4:
- e = frompow2(a, b, 2);
- break;
- case 8:
- e = from8(a, b);
- break;
- case 10:
- e = from10(a, b);
- break;
- case 16:
- e = frompow2(a, b, 4);
- break;
- default:
- abort();
- return nil;
- }
-
- if(pp != nil)
- *pp = e;
-
- // if no characters parsed, there wasn't a number to convert
- if(e == a)
- return nil;
-
- b->sign = sign;
- return mpnorm(b);
-}
--- a/llt/u16.c
+++ /dev/null
@@ -1,68 +1,0 @@
-#include "platform.h"
-
-#define between(x,min,max) (((min-1-x) & (x-max-1))>>8)
-
-int
-enc16chr(int o)
-{
- int c;
-
- c = between(o, 0, 9) & ('0'+o);
- c |= between(o, 10, 15) & ('A'+(o-10));
- return c;
-}
-
-int
-dec16chr(int c)
-{
- int o;
-
- o = between(c, '0', '9') & (1+(c-'0'));
- o |= between(c, 'A', 'F') & (1+10+(c-'A'));
- o |= between(c, 'a', 'f') & (1+10+(c-'a'));
- return o-1;
-}
-
-int
-dec16(uchar *out, int lim, char *in, int n)
-{
- int c, w = 0, i = 0;
- uchar *start = out;
- uchar *eout = out + lim;
-
- while(n-- > 0){
- c = dec16chr(*in++);
- if(c < 0)
- continue;
- w = (w<<4) + c;
- i++;
- if(i == 2){
- if(out + 1 > eout)
- goto exhausted;
- *out++ = w;
- w = 0;
- i = 0;
- }
- }
-exhausted:
- return out - start;
-}
-
-int
-enc16(char *out, int lim, uchar *in, int n)
-{
- uint c;
- char *eout = out + lim;
- char *start = out;
-
- while(n-- > 0){
- c = *in++;
- if(out + 2 >= eout)
- goto exhausted;
- *out++ = enc16chr(c>>4);
- *out++ = enc16chr(c&15);
- }
-exhausted:
- *out = 0;
- return out - start;
-}
--- a/llt/u32.c
+++ /dev/null
@@ -1,143 +1,0 @@
-#include "platform.h"
-
-#define between(x,min,max) (((min-1-x) & (x-max-1))>>8)
-
-int
-enc32chr(int o)
-{
- int c;
-
- c = between(o, 0, 25) & ('A'+o);
- c |= between(o, 26, 31) & ('2'+(o-26));
- return c;
-}
-
-int
-dec32chr(int c)
-{
- int o;
-
- o = between(c, 'A', 'Z') & (1+(c-'A'));
- o |= between(c, 'a', 'z') & (1+(c-'a'));
- o |= between(c, '2', '7') & (1+26+(c-'2'));
- return o-1;
-}
-
-int
-dec32x(uchar *dest, int ndest, char *src, int nsrc, int (*chr)(int))
-{
- uchar *start;
- int i, j, u[8];
-
- if(ndest+1 < (5*nsrc+7)/8)
- return -1;
- start = dest;
- while(nsrc>=8){
- for(i=0; i<8; i++){
- j = chr(src[i]);
- if(j < 0)
- j = 0;
- u[i] = j;
- }
- *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
- *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
- *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
- *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
- *dest++ = ((0x7 & u[6])<<5) | u[7];
- src += 8;
- nsrc -= 8;
- }
- if(nsrc > 0){
- if(nsrc == 1 || nsrc == 3 || nsrc == 6)
- return -1;
- for(i=0; i<nsrc; i++){
- j = chr(src[i]);
- if(j < 0)
- j = 0;
- u[i] = j;
- }
- *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
- if(nsrc == 2)
- goto out;
- *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
- if(nsrc == 4)
- goto out;
- *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
- if(nsrc == 5)
- goto out;
- *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
- }
-out:
- return dest-start;
-}
-
-int
-enc32x(char *dest, int ndest, uchar *src, int nsrc, int (*chr)(int))
-{
- char *start;
- int j;
-
- if(ndest <= (8*nsrc+4)/5)
- return -1;
- start = dest;
- while(nsrc>=5){
- j = (0x1f & (src[0]>>3));
- *dest++ = chr(j);
- j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
- *dest++ = chr(j);
- j = (0x1f & (src[1]>>1));
- *dest++ = chr(j);
- j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
- *dest++ = chr(j);
- j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
- *dest++ = chr(j);
- j = (0x1f & (src[3]>>2));
- *dest++ = chr(j);
- j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
- *dest++ = chr(j);
- j = (0x1f & (src[4]));
- *dest++ = chr(j);
- src += 5;
- nsrc -= 5;
- }
- if(nsrc){
- j = (0x1f & (src[0]>>3));
- *dest++ = chr(j);
- j = (0x1c & (src[0]<<2));
- if(nsrc == 1)
- goto out;
- j |= (0x03 & (src[1]>>6));
- *dest++ = chr(j);
- j = (0x1f & (src[1]>>1));
- *dest++ = chr(j);
- j = (0x10 & (src[1]<<4));
- if(nsrc == 2)
- goto out;
- j |= (0x0f & (src[2]>>4));
- *dest++ = chr(j);
- j = (0x1e & (src[2]<<1));
- if(nsrc == 3)
- goto out;
- j |= (0x01 & (src[3]>>7));
- *dest++ = chr(j);
- j = (0x1f & (src[3]>>2));
- *dest++ = chr(j);
- j = (0x18 & (src[3]<<3));
-out:
- *dest++ = chr(j);
- }
- *dest = 0;
- return dest-start;
-}
-
-int
-enc32(char *dest, int ndest, uchar *src, int nsrc)
-{
- return enc32x(dest, ndest, src, nsrc, enc32chr);
-}
-
-int
-dec32(uchar *dest, int ndest, char *src, int nsrc)
-{
- return dec32x(dest, ndest, src, nsrc, dec32chr);
-}
--- a/llt/u64.c
+++ /dev/null
@@ -1,141 +1,0 @@
-#include "platform.h"
-
-#define between(x,min,max) (((min-1-x) & (x-max-1))>>8)
-
-int
-enc64chr(int o)
-{
- int c;
-
- c = between(o, 0, 25) & ('A'+o);
- c |= between(o, 26, 51) & ('a'+(o-26));
- c |= between(o, 52, 61) & ('0'+(o-52));
- c |= between(o, 62, 62) & ('+');
- c |= between(o, 63, 63) & ('/');
- return c;
-}
-
-int
-dec64chr(int c)
-{
- int o;
-
- o = between(c, 'A', 'Z') & (1+(c-'A'));
- o |= between(c, 'a', 'z') & (1+26+(c-'a'));
- o |= between(c, '0', '9') & (1+52+(c-'0'));
- o |= between(c, '+', '+') & (1+62);
- o |= between(c, '/', '/') & (1+63);
- return o-1;
-}
-
-int
-dec64x(uchar *out, int lim, char *in, int n, int (*chr)(int))
-{
- ulong b24;
- uchar *start = out;
- uchar *e = out + lim;
- int i, c;
-
- b24 = 0;
- i = 0;
- while(n-- > 0){
- c = chr(*in++);
- if(c < 0)
- continue;
- switch(i){
- case 0:
- b24 = c<<18;
- break;
- case 1:
- b24 |= c<<12;
- break;
- case 2:
- b24 |= c<<6;
- break;
- case 3:
- if(out + 3 > e)
- goto exhausted;
-
- b24 |= c;
- *out++ = b24>>16;
- *out++ = b24>>8;
- *out++ = b24;
- i = 0;
- continue;
- }
- i++;
- }
- switch(i){
- case 2:
- if(out + 1 > e)
- goto exhausted;
- *out++ = b24>>16;
- break;
- case 3:
- if(out + 2 > e)
- goto exhausted;
- *out++ = b24>>16;
- *out++ = b24>>8;
- break;
- }
-exhausted:
- return out - start;
-}
-
-int
-enc64x(char *out, int lim, uchar *in, int n, int (*chr)(int))
-{
- int i;
- ulong b24;
- char *start = out;
- char *e = out + lim;
-
- for(i = n/3; i > 0; i--){
- b24 = *in++<<16;
- b24 |= *in++<<8;
- b24 |= *in++;
- if(out + 4 >= e)
- goto exhausted;
- *out++ = chr(b24>>18);
- *out++ = chr((b24>>12)&0x3f);
- *out++ = chr((b24>>6)&0x3f);
- *out++ = chr(b24&0x3f);
- }
-
- switch(n%3){
- case 2:
- b24 = *in++<<16;
- b24 |= *in<<8;
- if(out + 4 >= e)
- goto exhausted;
- *out++ = chr(b24>>18);
- *out++ = chr((b24>>12)&0x3f);
- *out++ = chr((b24>>6)&0x3f);
- *out++ = '=';
- break;
- case 1:
- b24 = *in<<16;
- if(out + 4 >= e)
- goto exhausted;
- *out++ = chr(b24>>18);
- *out++ = chr((b24>>12)&0x3f);
- *out++ = '=';
- *out++ = '=';
- break;
- }
-exhausted:
- *out = 0;
- return out - start;
-}
-
-int
-enc64(char *out, int lim, uchar *in, int n)
-{
- return enc64x(out, lim, in, n, enc64chr);
-}
-
-int
-dec64(uchar *out, int lim, char *in, int n)
-{
- return dec64x(out, lim, in, n, dec64chr);
-}
--- a/mkfile
+++ b/mkfile
@@ -25,16 +25,24 @@
iostream.$O\
string.$O\
table.$O\
+ llt/bitvector-ops.$O\
+ llt/bitvector.$O\
+ llt/dump.$O\
+ llt/hashing.$O\
+ llt/htable.$O\
+ llt/int2str.$O\
+ llt/ios.$O\
+ llt/lltinit.$O\
+ llt/ptrhash.$O\
+ llt/random.$O\
+ llt/timefuncs.$O\
+ llt/utf8.$O\
+ llt/wcwidth.$O\
default:V: all
</sys/src/cmd/mkone
-$O.out: llt/libllt.$O.a
-
-llt/libllt.$O.a:
- cd llt && mk
-
boot.h: flisp.boot
sed 's,\\,\\\\,g;s,",\\",g;s,^,",g;s,$,\\n",g' $prereq >$target
@@ -45,6 +53,9 @@
flisp.$O: maxstack.inc opcodes.h builtin_fns.h $CHFILES
+%.$O: %.c
+ $CC $CFLAGS -o $target $stem.c
+
bootstrap:V: $O.out
./$O.out gen.lsp && \
cp flisp.boot flisp.boot.bak && \
@@ -54,8 +65,6 @@
nuke:V:
rm -f *.[$OS] [$OS].out *.acid $TARG $CLEANFILES
- cd llt && mk nuke
clean:V:
rm -f *.[$OS] [$OS].out $TARG $CLEANFILES
- cd llt && mk clean
--- /dev/null
+++ b/mp/mpadd.c
@@ -1,0 +1,56 @@
+#include "platform.h"
+
+// sum = abs(b1) + abs(b2), i.e., add the magnitudes
+void
+mpmagadd(mpint *b1, mpint *b2, mpint *sum)
+{
+ int m, n;
+ mpint *t;
+
+ sum->flags |= (b1->flags | b2->flags) & MPtimesafe;
+
+ // get the sizes right
+ if(b2->top > b1->top){
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ }
+ n = b1->top;
+ m = b2->top;
+ if(n == 0){
+ mpassign(mpzero, sum);
+ return;
+ }
+ if(m == 0){
+ mpassign(b1, sum);
+ sum->sign = 1;
+ return;
+ }
+ mpbits(sum, (n+1)*Dbits);
+ sum->top = n+1;
+
+ mpvecadd(b1->p, n, b2->p, m, sum->p);
+ sum->sign = 1;
+
+ mpnorm(sum);
+}
+
+// sum = b1 + b2
+void
+mpadd(mpint *b1, mpint *b2, mpint *sum)
+{
+ int sign;
+
+ if(b1->sign != b2->sign){
+ assert(((b1->flags | b2->flags | sum->flags) & MPtimesafe) == 0);
+ if(b1->sign < 0)
+ mpmagsub(b2, b1, sum);
+ else
+ mpmagsub(b1, b2, sum);
+ } else {
+ sign = b1->sign;
+ mpmagadd(b1, b2, sum);
+ if(sum->top != 0)
+ sum->sign = sign;
+ }
+}
--- /dev/null
+++ b/mp/mpaux.c
@@ -1,0 +1,201 @@
+#include "platform.h"
+
+static mpdigit _mptwodata[1] = { 2 };
+static mpint _mptwo =
+{
+ 1, 1, 1,
+ _mptwodata,
+ MPstatic|MPnorm
+};
+mpint *mptwo = &_mptwo;
+
+static mpdigit _mponedata[1] = { 1 };
+static mpint _mpone =
+{
+ 1, 1, 1,
+ _mponedata,
+ MPstatic|MPnorm
+};
+mpint *mpone = &_mpone;
+
+static mpdigit _mpzerodata[1] = { 0 };
+static mpint _mpzero =
+{
+ 1, 1, 0,
+ _mpzerodata,
+ MPstatic|MPnorm
+};
+mpint *mpzero = &_mpzero;
+
+static int mpmindigits = 33;
+
+// set minimum digit allocation
+void
+mpsetminbits(int n)
+{
+ if(n < 0)
+ sysfatal("mpsetminbits: n < 0");
+ if(n == 0)
+ n = 1;
+ mpmindigits = DIGITS(n);
+}
+
+// allocate an n bit 0'd number
+mpint*
+mpnew(int n)
+{
+ mpint *b;
+
+ if(n < 0)
+ sysfatal("mpsetminbits: n < 0");
+
+ n = DIGITS(n);
+ if(n < mpmindigits)
+ n = mpmindigits;
+ b = calloc(1, sizeof(mpint) + n*Dbytes);
+ if(b == nil)
+ sysfatal("mpnew: %r");
+ b->p = (mpdigit*)&b[1];
+ b->size = n;
+ b->sign = 1;
+ b->flags = MPnorm;
+
+ return b;
+}
+
+// guarantee at least n significant bits
+void
+mpbits(mpint *b, int m)
+{
+ int n;
+
+ n = DIGITS(m);
+ if(b->size >= n){
+ if(b->top >= n)
+ return;
+ } else {
+ if(b->p == (mpdigit*)&b[1]){
+ b->p = (mpdigit*)malloc(n*Dbytes);
+ if(b->p == nil)
+ sysfatal("mpbits: %r");
+ memmove(b->p, &b[1], Dbytes*b->top);
+ memset(&b[1], 0, Dbytes*b->size);
+ } else {
+ b->p = (mpdigit*)realloc(b->p, n*Dbytes);
+ if(b->p == nil)
+ sysfatal("mpbits: %r");
+ }
+ b->size = n;
+ }
+ memset(&b->p[b->top], 0, Dbytes*(n - b->top));
+ b->top = n;
+ b->flags &= ~MPnorm;
+}
+
+void
+mpfree(mpint *b)
+{
+ if(b == nil)
+ return;
+ if(b->flags & MPstatic)
+ sysfatal("freeing mp constant");
+ memset(b->p, 0, b->size*Dbytes);
+ if(b->p != (mpdigit*)&b[1])
+ free(b->p);
+ free(b);
+}
+
+mpint*
+mpnorm(mpint *b)
+{
+ int i;
+
+ if(b->flags & MPtimesafe){
+ assert(b->sign == 1);
+ b->flags &= ~MPnorm;
+ return b;
+ }
+ for(i = b->top-1; i >= 0; i--)
+ if(b->p[i] != 0)
+ break;
+ b->top = i+1;
+ if(b->top == 0)
+ b->sign = 1;
+ b->flags |= MPnorm;
+ return b;
+}
+
+mpint*
+mpcopy(mpint *old)
+{
+ mpint *new;
+
+ new = mpnew(Dbits*old->size);
+ new->sign = old->sign;
+ new->top = old->top;
+ new->flags = old->flags & ~(MPstatic|MPfield);
+ memmove(new->p, old->p, Dbytes*old->top);
+ return new;
+}
+
+void
+mpassign(mpint *old, mpint *new)
+{
+ if(new == nil || old == new)
+ return;
+ new->top = 0;
+ mpbits(new, Dbits*old->top);
+ new->sign = old->sign;
+ new->top = old->top;
+ new->flags &= ~MPnorm;
+ new->flags |= old->flags & ~(MPstatic|MPfield);
+ memmove(new->p, old->p, Dbytes*old->top);
+}
+
+// number of significant bits in mantissa
+int
+mpsignif(mpint *n)
+{
+ int i, j;
+ mpdigit d;
+
+ if(n->top == 0)
+ return 0;
+ for(i = n->top-1; i >= 0; i--){
+ d = n->p[i];
+ for(j = Dbits-1; j >= 0; j--){
+ if(d & (((mpdigit)1)<<j))
+ return i*Dbits + j + 1;
+ }
+ }
+ return 0;
+}
+
+// k, where n = 2**k * q for odd q
+int
+mplowbits0(mpint *n)
+{
+ int k, bit, digit;
+ mpdigit d;
+
+ assert(n->flags & MPnorm);
+ if(n->top==0)
+ return 0;
+ k = 0;
+ bit = 0;
+ digit = 0;
+ d = n->p[0];
+ for(;;){
+ if(d & (1<<bit))
+ break;
+ k++;
+ bit++;
+ if(bit==Dbits){
+ if(++digit >= n->top)
+ return 0;
+ d = n->p[digit];
+ bit = 0;
+ }
+ }
+ return k;
+}
--- /dev/null
+++ b/mp/mpcmp.c
@@ -1,0 +1,28 @@
+#include "platform.h"
+
+// return neg, 0, pos as abs(b1)-abs(b2) is neg, 0, pos
+int
+mpmagcmp(mpint *b1, mpint *b2)
+{
+ int i;
+
+ i = b1->flags | b2->flags;
+ if(i & MPtimesafe)
+ return mpvectscmp(b1->p, b1->top, b2->p, b2->top);
+ if(i & MPnorm){
+ i = b1->top - b2->top;
+ if(i)
+ return i;
+ }
+ return mpveccmp(b1->p, b1->top, b2->p, b2->top);
+}
+
+// return neg, 0, pos as b1-b2 is neg, 0, pos
+int
+mpcmp(mpint *b1, mpint *b2)
+{
+ int sign;
+
+ sign = (b1->sign - b2->sign) >> 1; // -1, 0, 1
+ return sign | (sign&1)-1 & mpmagcmp(b1, b2)*b1->sign;
+}
--- /dev/null
+++ b/mp/mpdigdiv.c
@@ -1,0 +1,54 @@
+#include "platform.h"
+
+//
+// divide two digits by one and return quotient
+//
+void
+mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient)
+{
+ mpdigit hi, lo, q, x, y;
+ int i;
+
+ hi = dividend[1];
+ lo = dividend[0];
+
+ // return highest digit value if the result >= 2**32
+ if(hi >= divisor || divisor == 0){
+ divisor = 0;
+ *quotient = ~divisor;
+ return;
+ }
+
+ // very common case
+ if(~divisor == 0){
+ lo += hi;
+ if(lo < hi){
+ hi++;
+ lo++;
+ }
+ if(lo+1 == 0)
+ hi++;
+ *quotient = hi;
+ return;
+ }
+
+ // at this point we know that hi < divisor
+ // just shift and subtract till we're done
+ q = 0;
+ x = divisor;
+ for(i = Dbits-1; hi > 0 && i >= 0; i--){
+ x >>= 1;
+ if(x > hi)
+ continue;
+ y = divisor<<i;
+ if(x == hi && y > lo)
+ continue;
+ if(y > lo)
+ hi--;
+ lo -= y;
+ hi -= x;
+ q |= 1U<<i;
+ }
+ q += lo/divisor;
+ *quotient = q;
+}
--- /dev/null
+++ b/mp/mpdiv.c
@@ -1,0 +1,140 @@
+#include "platform.h"
+
+// division ala knuth, seminumerical algorithms, pp 237-238
+// the numbers are stored backwards to what knuth expects so j
+// counts down rather than up.
+
+void
+mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder)
+{
+ int j, s, vn, sign, qsign, rsign;
+ mpdigit qd, *up, *vp, *qp;
+ mpint *u, *v, *t;
+
+ assert(quotient != remainder);
+ assert(divisor->flags & MPnorm);
+
+ // divide bv zero
+ if(divisor->top == 0)
+ abort();
+
+ // division by one or small powers of two
+ if(divisor->top == 1 && (divisor->p[0] & divisor->p[0]-1) == 0){
+ vlong r = 0;
+ if(dividend->top > 0)
+ r = (vlong)dividend->sign * (dividend->p[0] & divisor->p[0]-1);
+ if(quotient != nil){
+ sign = divisor->sign;
+ for(s = 0; ((divisor->p[0] >> s) & 1) == 0; s++)
+ ;
+ mpright(dividend, s, quotient);
+ if(sign < 0)
+ quotient->sign ^= (-mpmagcmp(quotient, mpzero) >> 31) << 1;
+ }
+ if(remainder != nil){
+ remainder->flags |= dividend->flags & MPtimesafe;
+ vtomp(r, remainder);
+ }
+ return;
+ }
+ assert((dividend->flags & MPtimesafe) == 0);
+
+ // quick check
+ if(mpmagcmp(dividend, divisor) < 0){
+ if(remainder != nil)
+ mpassign(dividend, remainder);
+ if(quotient != nil)
+ mpassign(mpzero, quotient);
+ return;
+ }
+
+ qsign = divisor->sign * dividend->sign;
+ rsign = dividend->sign;
+
+ // D1: shift until divisor, v, has hi bit set (needed to make trial
+ // divisor accurate)
+ qd = divisor->p[divisor->top-1];
+ for(s = 0; (qd & mpdighi) == 0; s++)
+ qd <<= 1;
+ u = mpnew((dividend->top+2)*Dbits + s);
+ if(s == 0 && divisor != quotient && divisor != remainder) {
+ mpassign(dividend, u);
+ v = divisor;
+ } else {
+ mpleft(dividend, s, u);
+ v = mpnew(divisor->top*Dbits);
+ mpleft(divisor, s, v);
+ }
+ up = u->p+u->top-1;
+ vp = v->p+v->top-1;
+ vn = v->top;
+
+ // D1a: make sure high digit of dividend is less than high digit of divisor
+ if(*up >= *vp){
+ *++up = 0;
+ u->top++;
+ }
+
+ // storage for multiplies
+ t = mpnew(4*Dbits);
+
+ qp = nil;
+ if(quotient != nil){
+ mpbits(quotient, (u->top - v->top)*Dbits);
+ quotient->top = u->top - v->top;
+ qp = quotient->p+quotient->top-1;
+ }
+
+ // D2, D7: loop on length of dividend
+ for(j = u->top; j > vn; j--){
+
+ // D3: calculate trial divisor
+ mpdigdiv(up-1, *vp, &qd);
+
+ // D3a: rule out trial divisors 2 greater than real divisor
+ if(vn > 1) for(;;){
+ memset(t->p, 0, 3*Dbytes); // mpvecdigmuladd adds to what's there
+ mpvecdigmuladd(vp-1, 2, qd, t->p);
+ if(mpveccmp(t->p, 3, up-2, 3) > 0)
+ qd--;
+ else
+ break;
+ }
+
+ // D4: u -= v*qd << j*Dbits
+ sign = mpvecdigmulsub(v->p, vn, qd, up-vn);
+ if(sign < 0){
+
+ // D6: trial divisor was too high, add back borrowed
+ // value and decrease divisor
+ mpvecadd(up-vn, vn+1, v->p, vn, up-vn);
+ qd--;
+ }
+
+ // D5: save quotient digit
+ if(qp != nil)
+ *qp-- = qd;
+
+ // push top of u down one
+ u->top--;
+ *up-- = 0;
+ }
+ if(qp != nil){
+ assert((quotient->flags & MPtimesafe) == 0);
+ mpnorm(quotient);
+ if(quotient->top != 0)
+ quotient->sign = qsign;
+ }
+
+ if(remainder != nil){
+ assert((remainder->flags & MPtimesafe) == 0);
+ mpright(u, s, remainder); // u is the remainder shifted
+ if(remainder->top != 0)
+ remainder->sign = rsign;
+ }
+
+ mpfree(t);
+ mpfree(u);
+ if(v != divisor)
+ mpfree(v);
+}
--- /dev/null
+++ b/mp/mpfmt.c
@@ -1,0 +1,207 @@
+#include "platform.h"
+
+static int
+toencx(mpint *b, char *buf, int len, int (*enc)(char*, int, uchar*, int))
+{
+ uchar *p;
+ int n, rv;
+
+ p = nil;
+ n = mptobe(b, nil, 0, &p);
+ if(n < 0)
+ return -1;
+ rv = (*enc)(buf, len, p, n);
+ free(p);
+ return rv;
+}
+
+static int
+topow2(mpint *b, char *buf, int len, int s)
+{
+ mpdigit *p, x;
+ int i, j, sn;
+ char *out, *eout;
+
+ if(len < 1)
+ return -1;
+
+ sn = 1<<s;
+ out = buf;
+ eout = buf+len;
+ for(p = &b->p[b->top-1]; p >= b->p; p--){
+ x = *p;
+ for(i = Dbits-s; i >= 0; i -= s){
+ j = x >> i & sn - 1;
+ if(j != 0 || out != buf){
+ if(out >= eout)
+ return -1;
+ *out++ = enc16chr(j);
+ }
+ }
+ }
+ if(out == buf)
+ *out++ = '0';
+ if(out >= eout)
+ return -1;
+ *out = 0;
+ return 0;
+}
+
+static char*
+modbillion(int rem, ulong r, char *out, char *buf)
+{
+ ulong rr;
+ int i;
+
+ for(i = 0; i < 9; i++){
+ rr = r%10;
+ r /= 10;
+ if(out <= buf)
+ return nil;
+ *--out = '0' + rr;
+ if(rem == 0 && r == 0)
+ break;
+ }
+ return out;
+}
+
+static int
+to10(mpint *b, char *buf, int len)
+{
+ mpint *d, *r, *billion;
+ char *out;
+
+ if(len < 1)
+ return -1;
+
+ d = mpcopy(b);
+ d->flags &= ~MPtimesafe;
+ mpnorm(d);
+ r = mpnew(0);
+ billion = uitomp(1000000000, nil);
+ out = buf+len;
+ *--out = 0;
+ do {
+ mpdiv(d, billion, d, r);
+ out = modbillion(d->top, r->p[0], out, buf);
+ if(out == nil)
+ break;
+ } while(d->top != 0);
+ mpfree(d);
+ mpfree(r);
+ mpfree(billion);
+
+ if(out == nil)
+ return -1;
+ len -= out-buf;
+ if(out != buf)
+ memmove(buf, out, len);
+ return 0;
+}
+
+static int
+to8(mpint *b, char *buf, int len)
+{
+ mpdigit x, y;
+ char *out;
+ int i, j;
+
+ if(len < 2)
+ return -1;
+
+ out = buf+len;
+ *--out = 0;
+
+ i = j = 0;
+ x = y = 0;
+ while(j < b->top){
+ y = b->p[j++];
+ if(i > 0)
+ x |= y << i;
+ else
+ x = y;
+ i += Dbits;
+ while(i >= 3){
+Digout: i -= 3;
+ if(out > buf)
+ out--;
+ else if(x != 0)
+ return -1;
+ *out = '0' + (x & 7);
+ x = y >> (Dbits-i);
+ }
+ }
+ if(i > 0)
+ goto Digout;
+
+ while(*out == '0') out++;
+ if(*out == '\0')
+ *--out = '0';
+
+ len -= out-buf;
+ if(out != buf)
+ memmove(buf, out, len);
+ return 0;
+}
+
+char*
+mptoa(mpint *b, int base, char *buf, int len)
+{
+ char *out;
+ int rv, alloced;
+
+ if(base == 0)
+ base = 16; /* default */
+ alloced = 0;
+ if(buf == nil){
+ /* rv <= log₂(base) */
+ for(rv=1; (base >> rv) > 1; rv++)
+ ;
+ len = 10 + (b->top*Dbits / rv);
+ buf = malloc(len);
+ if(buf == nil)
+ return nil;
+ alloced = 1;
+ }
+
+ if(len < 2)
+ return nil;
+
+ out = buf;
+ if(b->sign < 0){
+ *out++ = '-';
+ len--;
+ }
+ switch(base){
+ case 64:
+ rv = toencx(b, out, len, enc64);
+ break;
+ case 32:
+ rv = toencx(b, out, len, enc32);
+ break;
+ case 16:
+ rv = topow2(b, out, len, 4);
+ break;
+ case 10:
+ rv = to10(b, out, len);
+ break;
+ case 8:
+ rv = to8(b, out, len);
+ break;
+ case 4:
+ rv = topow2(b, out, len, 2);
+ break;
+ case 2:
+ rv = topow2(b, out, len, 1);
+ break;
+ default:
+ abort();
+ return nil;
+ }
+ if(rv < 0){
+ if(alloced)
+ free(buf);
+ return nil;
+ }
+ return buf;
+}
--- /dev/null
+++ b/mp/mpleft.c
@@ -1,0 +1,49 @@
+#include "platform.h"
+
+// res = b << shift
+void
+mpleft(mpint *b, int shift, mpint *res)
+{
+ int d, l, r, i, otop;
+ mpdigit this, last;
+
+ res->sign = b->sign;
+ if(b->top==0){
+ res->top = 0;
+ return;
+ }
+
+ // a zero or negative left shift is a right shift
+ if(shift <= 0){
+ mpright(b, -shift, res);
+ return;
+ }
+
+ // b and res may be the same so remember the old top
+ otop = b->top;
+
+ // shift
+ mpbits(res, otop*Dbits + shift); // overkill
+ res->top = DIGITS(otop*Dbits + shift);
+ d = shift/Dbits;
+ l = shift - d*Dbits;
+ r = Dbits - l;
+
+ if(l == 0){
+ for(i = otop-1; i >= 0; i--)
+ res->p[i+d] = b->p[i];
+ } else {
+ last = 0;
+ for(i = otop-1; i >= 0; i--) {
+ this = b->p[i];
+ res->p[i+d+1] = (last<<l) | (this>>r);
+ last = this;
+ }
+ res->p[d] = last<<l;
+ }
+ for(i = 0; i < d; i++)
+ res->p[i] = 0;
+
+ res->flags |= b->flags & MPtimesafe;
+ mpnorm(res);
+}
--- /dev/null
+++ b/mp/mplogic.c
@@ -1,0 +1,210 @@
+#include "platform.h"
+
+/*
+ mplogic calculates b1|b2 subject to the
+ following flag bits (fl)
+
+ bit 0: subtract 1 from b1
+ bit 1: invert b1
+ bit 2: subtract 1 from b2
+ bit 3: invert b2
+ bit 4: add 1 to output
+ bit 5: invert output
+
+ it inverts appropriate bits automatically
+ depending on the signs of the inputs
+*/
+
+static void
+mplogic(mpint *b1, mpint *b2, mpint *sum, int fl)
+{
+ mpint *t;
+ mpdigit *dp1, *dp2, *dpo, d1, d2, d;
+ int c1, c2, co;
+ int i;
+
+ assert(((b1->flags | b2->flags | sum->flags) & MPtimesafe) == 0);
+ if(b1->sign < 0) fl ^= 0x03;
+ if(b2->sign < 0) fl ^= 0x0c;
+ sum->sign = (int)(((fl|fl>>2)^fl>>4)<<30)>>31|1;
+ if(sum->sign < 0) fl ^= 0x30;
+ if(b2->top > b1->top){
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ fl = fl >> 2 & 0x03 | fl << 2 & 0x0c | fl & 0x30;
+ }
+ mpbits(sum, b1->top*Dbits+1);
+ dp1 = b1->p;
+ dp2 = b2->p;
+ dpo = sum->p;
+ c1 = fl & 1;
+ c2 = fl >> 2 & 1;
+ co = fl >> 4 & 1;
+ for(i = 0; i < b1->top; i++){
+ d1 = dp1[i] - c1;
+ if(i < b2->top)
+ d2 = dp2[i] - c2;
+ else
+ d2 = 0;
+ if(d1 != (mpdigit)-1) c1 = 0;
+ if(d2 != (mpdigit)-1) c2 = 0;
+ if((fl & 2) != 0) d1 ^= -1;
+ if((fl & 8) != 0) d2 ^= -1;
+ d = d1 | d2;
+ if((fl & 32) != 0) d ^= -1;
+ d += co;
+ if(d != 0) co = 0;
+ dpo[i] = d;
+ }
+ sum->top = i;
+ if(co)
+ dpo[sum->top++] = co;
+ mpnorm(sum);
+}
+
+void
+mpor(mpint *b1, mpint *b2, mpint *sum)
+{
+ mplogic(b1, b2, sum, 0);
+}
+
+void
+mpand(mpint *b1, mpint *b2, mpint *sum)
+{
+ mplogic(b1, b2, sum, 0x2a);
+}
+
+void
+mpbic(mpint *b1, mpint *b2, mpint *sum)
+{
+ mplogic(b1, b2, sum, 0x22);
+}
+
+void
+mpnot(mpint *b, mpint *r)
+{
+ mpadd(b, mpone, r);
+ if(r->top != 0)
+ r->sign ^= -2;
+}
+
+void
+mpxor(mpint *b1, mpint *b2, mpint *sum)
+{
+ mpint *t;
+ mpdigit *dp1, *dp2, *dpo, d1, d2, d;
+ int c1, c2, co;
+ int i, fl;
+
+ assert(((b1->flags | b2->flags | sum->flags) & MPtimesafe) == 0);
+ if(b2->top > b1->top){
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ }
+ fl = (b1->sign & 10) ^ (b2->sign & 12);
+ sum->sign = (int)(fl << 28) >> 31 | 1;
+ mpbits(sum, b1->top*Dbits+1);
+ dp1 = b1->p;
+ dp2 = b2->p;
+ dpo = sum->p;
+ c1 = fl >> 1 & 1;
+ c2 = fl >> 2 & 1;
+ co = fl >> 3 & 1;
+ for(i = 0; i < b1->top; i++){
+ d1 = dp1[i] - c1;
+ if(i < b2->top)
+ d2 = dp2[i] - c2;
+ else
+ d2 = 0;
+ if(d1 != (mpdigit)-1) c1 = 0;
+ if(d2 != (mpdigit)-1) c2 = 0;
+ d = d1 ^ d2;
+ d += co;
+ if(d != 0) co = 0;
+ dpo[i] = d;
+ }
+ sum->top = i;
+ if(co)
+ dpo[sum->top++] = co;
+ mpnorm(sum);
+}
+
+void
+mptrunc(mpint *b, int n, mpint *r)
+{
+ int d, m, i, c;
+
+ assert(((b->flags | r->flags) & MPtimesafe) == 0);
+ mpbits(r, n);
+ r->top = DIGITS(n);
+ d = n / Dbits;
+ m = n % Dbits;
+ if(b->sign == -1){
+ c = 1;
+ for(i = 0; i < r->top; i++){
+ if(i < b->top)
+ r->p[i] = ~(b->p[i] - c);
+ else
+ r->p[i] = -1;
+ if(r->p[i] != 0)
+ c = 0;
+ }
+ if(m != 0)
+ r->p[d] &= (1<<m) - 1;
+ }else if(b->sign == 1){
+ if(d >= b->top){
+ mpassign(b, r);
+ mpnorm(r);
+ return;
+ }
+ if(b != r)
+ for(i = 0; i < d; i++)
+ r->p[i] = b->p[i];
+ if(m != 0)
+ r->p[d] = b->p[d] & (1<<m)-1;
+ }
+ r->sign = 1;
+ mpnorm(r);
+}
+
+void
+mpxtend(mpint *b, int n, mpint *r)
+{
+ int d, m, c, i;
+
+ d = (n - 1) / Dbits;
+ m = (n - 1) % Dbits;
+ if(d >= b->top){
+ mpassign(b, r);
+ return;
+ }
+ mptrunc(b, n, r);
+ mpbits(r, n);
+ if((r->p[d] & 1<<m) == 0){
+ mpnorm(r);
+ return;
+ }
+ r->p[d] |= -(1<<m);
+ r->sign = -1;
+ c = 1;
+ for(i = 0; i < r->top; i++){
+ r->p[i] = ~(r->p[i] - c);
+ if(r->p[i] != 0)
+ c = 0;
+ }
+ mpnorm(r);
+}
+
+void
+mpasr(mpint *b, int n, mpint *r)
+{
+ if(b->sign > 0 || n <= 0){
+ mpright(b, n, r);
+ return;
+ }
+ mpadd(b, mpone, r);
+ mpright(r, n, r);
+ mpsub(r, mpone, r);
+}
--- /dev/null
+++ b/mp/mpmul.c
@@ -1,0 +1,174 @@
+#include "platform.h"
+
+//
+// from knuth's 1969 seminumberical algorithms, pp 233-235 and pp 258-260
+//
+// mpvecmul is an assembly language routine that performs the inner
+// loop.
+//
+// the karatsuba trade off is set empiricly by measuring the algs on
+// a 400 MHz Pentium II.
+//
+
+// karatsuba like (see knuth pg 258)
+// prereq: p is already zeroed
+static void
+mpkaratsuba(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
+{
+ mpdigit *t, *u0, *u1, *v0, *v1, *u0v0, *u1v1, *res, *diffprod;
+ int u0len, u1len, v0len, v1len, reslen;
+ int sign, n;
+
+ // divide each piece in half
+ n = alen/2;
+ if(alen&1)
+ n++;
+ u0len = n;
+ u1len = alen-n;
+ if(blen > n){
+ v0len = n;
+ v1len = blen-n;
+ } else {
+ v0len = blen;
+ v1len = 0;
+ }
+ u0 = a;
+ u1 = a + u0len;
+ v0 = b;
+ v1 = b + v0len;
+
+ // room for the partial products
+ t = calloc(1, Dbytes*5*(2*n+1));
+ if(t == nil)
+ sysfatal("mpkaratsuba: %r");
+ u0v0 = t;
+ u1v1 = t + (2*n+1);
+ diffprod = t + 2*(2*n+1);
+ res = t + 3*(2*n+1);
+ reslen = 4*n+1;
+
+ // t[0] = (u1-u0)
+ sign = 1;
+ if(mpveccmp(u1, u1len, u0, u0len) < 0){
+ sign = -1;
+ mpvecsub(u0, u0len, u1, u1len, u0v0);
+ } else
+ mpvecsub(u1, u1len, u0, u1len, u0v0);
+
+ // t[1] = (v0-v1)
+ if(mpveccmp(v0, v0len, v1, v1len) < 0){
+ sign *= -1;
+ mpvecsub(v1, v1len, v0, v1len, u1v1);
+ } else
+ mpvecsub(v0, v0len, v1, v1len, u1v1);
+
+ // t[4:5] = (u1-u0)*(v0-v1)
+ mpvecmul(u0v0, u0len, u1v1, v0len, diffprod);
+
+ // t[0:1] = u1*v1
+ memset(t, 0, 2*(2*n+1)*Dbytes);
+ if(v1len > 0)
+ mpvecmul(u1, u1len, v1, v1len, u1v1);
+
+ // t[2:3] = u0v0
+ mpvecmul(u0, u0len, v0, v0len, u0v0);
+
+ // res = u0*v0<<n + u0*v0
+ mpvecadd(res, reslen, u0v0, u0len+v0len, res);
+ mpvecadd(res+n, reslen-n, u0v0, u0len+v0len, res+n);
+
+ // res += u1*v1<<n + u1*v1<<2*n
+ if(v1len > 0){
+ mpvecadd(res+n, reslen-n, u1v1, u1len+v1len, res+n);
+ mpvecadd(res+2*n, reslen-2*n, u1v1, u1len+v1len, res+2*n);
+ }
+
+ // res += (u1-u0)*(v0-v1)<<n
+ if(sign < 0)
+ mpvecsub(res+n, reslen-n, diffprod, u0len+v0len, res+n);
+ else
+ mpvecadd(res+n, reslen-n, diffprod, u0len+v0len, res+n);
+ memmove(p, res, (alen+blen)*Dbytes);
+
+ free(t);
+}
+
+#define KARATSUBAMIN 32
+
+void
+mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
+{
+ int i;
+ mpdigit d;
+ mpdigit *t;
+
+ // both mpvecdigmuladd and karatsuba are fastest when a is the longer vector
+ if(alen < blen){
+ i = alen;
+ alen = blen;
+ blen = i;
+ t = a;
+ a = b;
+ b = t;
+ }
+
+ if(alen >= KARATSUBAMIN && blen > 1){
+ // O(n^1.585)
+ mpkaratsuba(a, alen, b, blen, p);
+ } else {
+ // O(n^2)
+ for(i = 0; i < blen; i++){
+ d = b[i];
+ if(d != 0)
+ mpvecdigmuladd(a, alen, d, &p[i]);
+ }
+ }
+}
+
+void
+mpvectsmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
+{
+ int i;
+ mpdigit *t;
+
+ if(alen < blen){
+ i = alen;
+ alen = blen;
+ blen = i;
+ t = a;
+ a = b;
+ b = t;
+ }
+ if(blen == 0)
+ return;
+ for(i = 0; i < blen; i++)
+ mpvecdigmuladd(a, alen, b[i], &p[i]);
+}
+
+void
+mpmul(mpint *b1, mpint *b2, mpint *prod)
+{
+ mpint *oprod;
+
+ oprod = prod;
+ if(prod == b1 || prod == b2){
+ prod = mpnew(0);
+ prod->flags = oprod->flags;
+ }
+ prod->flags |= (b1->flags | b2->flags) & MPtimesafe;
+
+ prod->top = 0;
+ mpbits(prod, (b1->top+b2->top+1)*Dbits);
+ if(prod->flags & MPtimesafe)
+ mpvectsmul(b1->p, b1->top, b2->p, b2->top, prod->p);
+ else
+ mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p);
+ prod->top = b1->top+b2->top+1;
+ prod->sign = b1->sign*b2->sign;
+ mpnorm(prod);
+
+ if(oprod != prod){
+ mpassign(prod, oprod);
+ mpfree(prod);
+ }
+}
--- /dev/null
+++ b/mp/mpright.c
@@ -1,0 +1,55 @@
+#include "platform.h"
+
+// res = b >> shift
+void
+mpright(mpint *b, int shift, mpint *res)
+{
+ int d, l, r, i;
+ mpdigit this, last;
+
+ res->sign = b->sign;
+ if(b->top==0){
+ res->top = 0;
+ return;
+ }
+
+ // a negative right shift is a left shift
+ if(shift < 0){
+ mpleft(b, -shift, res);
+ return;
+ }
+
+ if(res != b)
+ mpbits(res, b->top*Dbits - shift);
+ else if(shift == 0)
+ return;
+
+ d = shift/Dbits;
+ r = shift - d*Dbits;
+ l = Dbits - r;
+
+ // shift all the bits out == zero
+ if(d>=b->top){
+ res->sign = 1;
+ res->top = 0;
+ return;
+ }
+
+ // special case digit shifts
+ if(r == 0){
+ for(i = 0; i < b->top-d; i++)
+ res->p[i] = b->p[i+d];
+ } else {
+ last = b->p[d];
+ for(i = 0; i < b->top-d-1; i++){
+ this = b->p[i+d+1];
+ res->p[i] = (this<<l) | (last>>r);
+ last = this;
+ }
+ res->p[i++] = last>>r;
+ }
+
+ res->top = i;
+ res->flags |= b->flags & MPtimesafe;
+ mpnorm(res);
+}
--- /dev/null
+++ b/mp/mpsub.c
@@ -1,0 +1,54 @@
+#include "platform.h"
+
+// diff = abs(b1) - abs(b2), i.e., subtract the magnitudes
+void
+mpmagsub(mpint *b1, mpint *b2, mpint *diff)
+{
+ int n, m, sign;
+ mpint *t;
+
+ // get the sizes right
+ if(mpmagcmp(b1, b2) < 0){
+ assert(((b1->flags | b2->flags | diff->flags) & MPtimesafe) == 0);
+ sign = -1;
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ } else {
+ diff->flags |= (b1->flags | b2->flags) & MPtimesafe;
+ sign = 1;
+ }
+ n = b1->top;
+ m = b2->top;
+ if(m == 0){
+ mpassign(b1, diff);
+ diff->sign = sign;
+ return;
+ }
+ mpbits(diff, n*Dbits);
+
+ mpvecsub(b1->p, n, b2->p, m, diff->p);
+ diff->sign = sign;
+ diff->top = n;
+ mpnorm(diff);
+}
+
+// diff = b1 - b2
+void
+mpsub(mpint *b1, mpint *b2, mpint *diff)
+{
+ int sign;
+
+ if(b1->sign != b2->sign){
+ assert(((b1->flags | b2->flags | diff->flags) & MPtimesafe) == 0);
+ sign = b1->sign;
+ mpmagadd(b1, b2, diff);
+ diff->sign = sign;
+ return;
+ }
+
+ sign = b1->sign;
+ mpmagsub(b1, b2, diff);
+ if(diff->top != 0)
+ diff->sign *= sign;
+}
--- /dev/null
+++ b/mp/mptobe.c
@@ -1,0 +1,29 @@
+#include "platform.h"
+
+// convert an mpint into a big endian byte array (most significant byte first; left adjusted)
+// return number of bytes converted
+// if p == nil, allocate and result array
+int
+mptobe(mpint *b, uchar *p, uint n, uchar **pp)
+{
+ uint m;
+
+ m = (mpsignif(b)+7)/8;
+ if(m == 0)
+ m++;
+ if(p == nil){
+ n = m;
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("mptobe: %r");
+ } else {
+ if(n < m)
+ return -1;
+ if(n > m)
+ memset(p+m, 0, n-m);
+ }
+ if(pp != nil)
+ *pp = p;
+ mptober(b, p, m);
+ return m;
+}
--- /dev/null
+++ b/mp/mptober.c
@@ -1,0 +1,32 @@
+#include "platform.h"
+
+void
+mptober(mpint *b, uchar *p, int n)
+{
+ int i, j, m;
+ mpdigit x;
+
+ memset(p, 0, n);
+
+ p += n;
+ m = b->top*Dbytes;
+ if(m < n)
+ n = m;
+
+ i = 0;
+ while(n >= Dbytes){
+ n -= Dbytes;
+ x = b->p[i++];
+ for(j = 0; j < Dbytes; j++){
+ *--p = x;
+ x >>= 8;
+ }
+ }
+ if(n > 0){
+ x = b->p[i];
+ for(j = 0; j < n; j++){
+ *--p = x;
+ x >>= 8;
+ }
+ }
+}
--- /dev/null
+++ b/mp/mptod.c
@@ -1,0 +1,83 @@
+#include "platform.h"
+
+extern double D_PINF, D_NINF;
+
+double
+mptod(mpint *a)
+{
+ u64int v;
+ mpdigit w, r;
+ int sf, i, n, m, s;
+ FPdbleword x;
+
+ if(a->top == 0) return 0.0;
+ sf = mpsignif(a);
+ if(sf > 1024) return a->sign < 0 ? D_NINF : D_PINF;
+ i = a->top - 1;
+ v = a->p[i];
+ n = sf & Dbits - 1;
+ n |= n - 1 & Dbits;
+ r = 0;
+ if(n > 54){
+ s = n - 54;
+ r = v & (1<<s) - 1;
+ v >>= s;
+ }
+ while(n < 54){
+ if(--i < 0)
+ w = 0;
+ else
+ w = a->p[i];
+ m = 54 - n;
+ if(m > Dbits) m = Dbits;
+ s = Dbits - m & Dbits - 1;
+ v = v << m | w >> s;
+ r = w & (1<<s) - 1;
+ n += m;
+ }
+ if((v & 3) == 1){
+ while(--i >= 0)
+ r |= a->p[i];
+ if(r != 0)
+ v++;
+ }else
+ v++;
+ v >>= 1;
+ while((v >> 53) != 0){
+ v >>= 1;
+ if(++sf > 1024)
+ return a->sign < 0 ? D_NINF : D_PINF;
+ }
+ x.lo = v;
+ x.hi = (u32int)(v >> 32) & (1<<20) - 1 | (sf + 1022) << 20 | a->sign & 1<<31;
+ return x.x;
+}
+
+mpint *
+dtomp(double d, mpint *a)
+{
+ FPdbleword x;
+ uvlong v;
+ int e;
+
+ if(a == nil)
+ a = mpnew(0);
+ x.x = d;
+ e = x.hi >> 20 & 2047;
+ assert(e != 2047);
+ if(e < 1022){
+ mpassign(mpzero, a);
+ return a;
+ }
+ v = x.lo | (uvlong)(x.hi & (1<<20) - 1) << 32 | 1ULL<<52;
+ if(e < 1075){
+ v += (1ULL<<(1074 - e)) - (~v >> (1075 - e) & 1);
+ v >>= 1075 - e;
+ }
+ uvtomp(v, a);
+ if(e > 1075)
+ mpleft(a, e - 1075, a);
+ if((int)x.hi < 0)
+ a->sign = -1;
+ return a;
+}
--- /dev/null
+++ b/mp/mptoi.c
@@ -1,0 +1,41 @@
+#include "platform.h"
+
+/*
+ * this code assumes that mpdigit is at least as
+ * big as an int.
+ */
+
+mpint*
+itomp(int i, mpint *b)
+{
+ if(b == nil){
+ b = mpnew(0);
+ }
+ b->sign = (i >> (sizeof(i)*8 - 1)) | 1;
+ i *= b->sign;
+ *b->p = i;
+ b->top = 1;
+ return mpnorm(b);
+}
+
+int
+mptoi(mpint *b)
+{
+ uint x;
+
+ if(b->top==0)
+ return 0;
+ x = *b->p;
+ if(b->sign > 0){
+ if(b->top > 1 || (x > MAXINT))
+ x = (int)MAXINT;
+ else
+ x = (int)x;
+ } else {
+ if(b->top > 1 || x > MAXINT+1)
+ x = (int)MININT;
+ else
+ x = -(int)x;
+ }
+ return x;
+}
--- /dev/null
+++ b/mp/mptoui.c
@@ -1,0 +1,31 @@
+#include "platform.h"
+
+/*
+ * this code assumes that mpdigit is at least as
+ * big as an int.
+ */
+
+mpint*
+uitomp(uint i, mpint *b)
+{
+ if(b == nil){
+ b = mpnew(0);
+ }
+ *b->p = i;
+ b->top = 1;
+ b->sign = 1;
+ return mpnorm(b);
+}
+
+uint
+mptoui(mpint *b)
+{
+ uint x;
+
+ x = *b->p;
+ if(b->sign < 0)
+ x = 0;
+ else if(b->top > 1 || (sizeof(mpdigit) > sizeof(uint) && x > MAXUINT))
+ x = MAXUINT;
+ return x;
+}
--- /dev/null
+++ b/mp/mptouv.c
@@ -1,0 +1,44 @@
+#include "platform.h"
+
+#define VLDIGITS (int)(sizeof(vlong)/sizeof(mpdigit))
+
+/*
+ * this code assumes that a vlong is an integral number of
+ * mpdigits long.
+ */
+mpint*
+uvtomp(uvlong v, mpint *b)
+{
+ int s;
+
+ if(b == nil){
+ b = mpnew(VLDIGITS*Dbits);
+ }else
+ mpbits(b, VLDIGITS*Dbits);
+ b->sign = 1;
+ for(s = 0; s < VLDIGITS; s++){
+ b->p[s] = v;
+ v >>= sizeof(mpdigit)*8;
+ }
+ b->top = s;
+ return mpnorm(b);
+}
+
+uvlong
+mptouv(mpint *b)
+{
+ uvlong v;
+ int s;
+
+ if(b->top == 0 || b->sign < 0)
+ return 0LL;
+
+ if(b->top > VLDIGITS)
+ return -1LL;
+
+ v = 0ULL;
+ for(s = 0; s < b->top; s++)
+ v |= (uvlong)b->p[s]<<(s*sizeof(mpdigit)*8);
+
+ return v;
+}
--- /dev/null
+++ b/mp/mptov.c
@@ -1,0 +1,60 @@
+#include "platform.h"
+
+#define VLDIGITS (int)(sizeof(vlong)/sizeof(mpdigit))
+
+/*
+ * this code assumes that a vlong is an integral number of
+ * mpdigits long.
+ */
+mpint*
+vtomp(vlong v, mpint *b)
+{
+ int s;
+ uvlong uv;
+
+ if(b == nil){
+ b = mpnew(VLDIGITS*Dbits);
+ }else
+ mpbits(b, VLDIGITS*Dbits);
+ b->sign = (v >> (sizeof(v)*8 - 1)) | 1;
+ uv = v * b->sign;
+ for(s = 0; s < VLDIGITS; s++){
+ b->p[s] = uv;
+ uv >>= sizeof(mpdigit)*8;
+ }
+ b->top = s;
+ return mpnorm(b);
+}
+
+vlong
+mptov(mpint *b)
+{
+ uvlong v;
+ int s;
+
+ if(b->top == 0)
+ return 0LL;
+
+ if(b->top > VLDIGITS){
+ if(b->sign > 0)
+ return (vlong)MAXVLONG;
+ else
+ return (vlong)MINVLONG;
+ }
+
+ v = 0ULL;
+ for(s = 0; s < b->top; s++)
+ v |= (uvlong)b->p[s]<<(s*sizeof(mpdigit)*8);
+
+ if(b->sign > 0){
+ if(v > MAXVLONG)
+ v = MAXVLONG;
+ } else {
+ if(v > MINVLONG)
+ v = MINVLONG;
+ else
+ v = -(vlong)v;
+ }
+
+ return (vlong)v;
+}
--- /dev/null
+++ b/mp/mpvecadd.c
@@ -1,0 +1,34 @@
+#include "platform.h"
+
+// prereq: alen >= blen, sum has at least blen+1 digits
+void
+mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+{
+ int i;
+ uint carry;
+ mpdigit x, y;
+
+ carry = 0;
+ for(i = 0; i < blen; i++){
+ x = *a++;
+ y = *b++;
+ x += carry;
+ if(x < carry)
+ carry = 1;
+ else
+ carry = 0;
+ x += y;
+ if(x < y)
+ carry++;
+ *sum++ = x;
+ }
+ for(; i < alen; i++){
+ x = *a++ + carry;
+ if(x < carry)
+ carry = 1;
+ else
+ carry = 0;
+ *sum++ = x;
+ }
+ *sum = carry;
+}
--- /dev/null
+++ b/mp/mpveccmp.c
@@ -1,0 +1,25 @@
+#include "platform.h"
+
+int
+mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen)
+{
+ mpdigit x;
+
+ while(alen > blen)
+ if(a[--alen] != 0)
+ return 1;
+ while(blen > alen)
+ if(b[--blen] != 0)
+ return -1;
+ while(alen > 0){
+ --alen;
+ x = a[alen] - b[alen];
+ if(x == 0)
+ continue;
+ if(x > a[alen])
+ return -1;
+ else
+ return 1;
+ }
+ return 0;
+}
--- /dev/null
+++ b/mp/mpvecdigmuladd.c
@@ -1,0 +1,101 @@
+#include "platform.h"
+
+#define LO(x) ((x) & ((1<<(Dbits/2))-1))
+#define HI(x) ((x) >> (Dbits/2))
+
+static void
+mpdigmul(mpdigit a, mpdigit b, mpdigit *p)
+{
+ mpdigit x, ah, al, bh, bl, p1, p2, p3, p4;
+ int carry;
+
+ // half digits
+ ah = HI(a);
+ al = LO(a);
+ bh = HI(b);
+ bl = LO(b);
+
+ // partial products
+ p1 = ah*bl;
+ p2 = bh*al;
+ p3 = bl*al;
+ p4 = ah*bh;
+
+ // p = ((p1+p2)<<(Dbits/2)) + (p4<<Dbits) + p3
+ carry = 0;
+ x = p1<<(Dbits/2);
+ p3 += x;
+ if(p3 < x)
+ carry++;
+ x = p2<<(Dbits/2);
+ p3 += x;
+ if(p3 < x)
+ carry++;
+ p4 += carry + HI(p1) + HI(p2); // can't carry out of the high digit
+ p[0] = p3;
+ p[1] = p4;
+}
+
+// prereq: p must have room for n+1 digits
+void
+mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+{
+ int i;
+ mpdigit carry, x, y, part[2];
+
+ carry = 0;
+ part[1] = 0;
+ for(i = 0; i < n; i++){
+ x = part[1] + carry;
+ if(x < carry)
+ carry = 1;
+ else
+ carry = 0;
+ y = *p;
+ mpdigmul(*b++, m, part);
+ x += part[0];
+ if(x < part[0])
+ carry++;
+ x += y;
+ if(x < y)
+ carry++;
+ *p++ = x;
+ }
+ *p = part[1] + carry;
+}
+
+// prereq: p must have room for n+1 digits
+int
+mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+{
+ int i;
+ mpdigit x, y, part[2], borrow;
+
+ borrow = 0;
+ part[1] = 0;
+ for(i = 0; i < n; i++){
+ x = *p;
+ y = x - borrow;
+ if(y > x)
+ borrow = 1;
+ else
+ borrow = 0;
+ x = part[1];
+ mpdigmul(*b++, m, part);
+ x += part[0];
+ if(x < part[0])
+ borrow++;
+ x = y - x;
+ if(x > y)
+ borrow++;
+ *p++ = x;
+ }
+
+ x = *p;
+ y = x - borrow - part[1];
+ *p = y;
+ if(y > x)
+ return -1;
+ else
+ return 1;
+}
--- /dev/null
+++ b/mp/mpvecsub.c
@@ -1,0 +1,32 @@
+#include "platform.h"
+
+// prereq: a >= b, alen >= blen, diff has at least alen digits
+void
+mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+{
+ int i, borrow;
+ mpdigit x, y;
+
+ borrow = 0;
+ for(i = 0; i < blen; i++){
+ x = *a++;
+ y = *b++;
+ y += borrow;
+ if(y < (mpdigit)borrow)
+ borrow = 1;
+ else
+ borrow = 0;
+ if(x < y)
+ borrow++;
+ *diff++ = x - y;
+ }
+ for(; i < alen; i++){
+ x = *a++;
+ y = x - borrow;
+ if(y > x)
+ borrow = 1;
+ else
+ borrow = 0;
+ *diff++ = y;
+ }
+}
--- /dev/null
+++ b/mp/mpvectscmp.c
@@ -1,0 +1,32 @@
+#include "platform.h"
+
+int
+mpvectscmp(mpdigit *a, int alen, mpdigit *b, int blen)
+{
+ mpdigit x, y, z, v;
+ int m, p;
+
+ if(alen > blen){
+ v = 0;
+ while(alen > blen)
+ v |= a[--alen];
+ m = p = (-v^v|v)>>(Dbits-1);
+ } else if(blen > alen){
+ v = 0;
+ while(blen > alen)
+ v |= b[--blen];
+ m = (-v^v|v)>>(Dbits-1);
+ p = m^1;
+ } else
+ m = p = 0;
+ while(alen-- > 0){
+ x = a[alen];
+ y = b[alen];
+ z = x - y;
+ x = ~x;
+ v = ((-z^z|z)>>(Dbits-1)) & ~m;
+ p = ((~(x&y|x&z|y&z)>>(Dbits-1)) & v) | (p & ~v);
+ m |= v;
+ }
+ return (p-m) | m;
+}
--- /dev/null
+++ b/mp/strtomp.c
@@ -1,0 +1,174 @@
+#include "platform.h"
+
+static char*
+frompow2(char *a, mpint *b, int s)
+{
+ char *p, *next;
+ mpdigit x;
+ int i;
+
+ i = 1<<s;
+ for(p = a; (dec16chr(*p) & 255) < i; p++)
+ ;
+
+ mpbits(b, (p-a)*s);
+ b->top = 0;
+ next = p;
+
+ while(p > a){
+ x = 0;
+ for(i = 0; i < Dbits; i += s){
+ if(p <= a)
+ break;
+ x |= dec16chr(*--p)<<i;
+ }
+ b->p[b->top++] = x;
+ }
+ return next;
+}
+
+static char*
+from8(char *a, mpint *b)
+{
+ char *p, *next;
+ mpdigit x, y;
+ int i;
+
+ for(p = a; ((*p - '0') & 255) < 8; p++)
+ ;
+
+ mpbits(b, (p-a)*3);
+ b->top = 0;
+ next = p;
+
+ i = 0;
+ x = y = 0;
+ while(p > a){
+ y = *--p - '0';
+ x |= y << i;
+ i += 3;
+ if(i >= Dbits){
+Digout:
+ i -= Dbits;
+ b->p[b->top++] = x;
+ x = y >> (3-i);
+ }
+ }
+ if(i > 0)
+ goto Digout;
+
+ return next;
+}
+
+static ulong mppow10[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
+};
+
+static char*
+from10(char *a, mpint *b)
+{
+ ulong x, y;
+ mpint *pow, *r;
+ int i;
+
+ pow = mpnew(0);
+ r = mpnew(0);
+
+ b->top = 0;
+ for(;;){
+ // do a billion at a time in native arithmetic
+ x = 0;
+ for(i = 0; i < 9; i++){
+ y = *a - '0';
+ if(y > 9)
+ break;
+ a++;
+ x *= 10;
+ x += y;
+ }
+ if(i == 0)
+ break;
+
+ // accumulate into mpint
+ uitomp(mppow10[i], pow);
+ uitomp(x, r);
+ mpmul(b, pow, b);
+ mpadd(b, r, b);
+ if(i < 9)
+ break;
+ }
+ mpfree(pow);
+ mpfree(r);
+ return a;
+}
+
+mpint*
+strtomp(char *a, char **pp, int base, mpint *b)
+{
+ int sign;
+ char *e;
+
+ if(b == nil){
+ b = mpnew(0);
+ }
+
+ while(*a==' ' || *a=='\t')
+ a++;
+
+ sign = 1;
+ for(;; a++){
+ switch(*a){
+ case '-':
+ sign *= -1;
+ continue;
+ }
+ break;
+ }
+
+ if(base == 0){
+ base = 10;
+ if(a[0] == '0'){
+ if(a[1] == 'x' || a[1] == 'X') {
+ a += 2;
+ base = 16;
+ } else if(a[1] == 'b' || a[1] == 'B') {
+ a += 2;
+ base = 2;
+ } else if(a[1] >= '0' && a[1] <= '7') {
+ a++;
+ base = 8;
+ }
+ }
+ }
+
+ switch(base){
+ case 2:
+ e = frompow2(a, b, 1);
+ break;
+ case 4:
+ e = frompow2(a, b, 2);
+ break;
+ case 8:
+ e = from8(a, b);
+ break;
+ case 10:
+ e = from10(a, b);
+ break;
+ case 16:
+ e = frompow2(a, b, 4);
+ break;
+ default:
+ abort();
+ return nil;
+ }
+
+ if(pp != nil)
+ *pp = e;
+
+ // if no characters parsed, there wasn't a number to convert
+ if(e == a)
+ return nil;
+
+ b->sign = sign;
+ return mpnorm(b);
+}
--- /dev/null
+++ b/mp/u16.c
@@ -1,0 +1,68 @@
+#include "platform.h"
+
+#define between(x,min,max) (((min-1-x) & (x-max-1))>>8)
+
+int
+enc16chr(int o)
+{
+ int c;
+
+ c = between(o, 0, 9) & ('0'+o);
+ c |= between(o, 10, 15) & ('A'+(o-10));
+ return c;
+}
+
+int
+dec16chr(int c)
+{
+ int o;
+
+ o = between(c, '0', '9') & (1+(c-'0'));
+ o |= between(c, 'A', 'F') & (1+10+(c-'A'));
+ o |= between(c, 'a', 'f') & (1+10+(c-'a'));
+ return o-1;
+}
+
+int
+dec16(uchar *out, int lim, char *in, int n)
+{
+ int c, w = 0, i = 0;
+ uchar *start = out;
+ uchar *eout = out + lim;
+
+ while(n-- > 0){
+ c = dec16chr(*in++);
+ if(c < 0)
+ continue;
+ w = (w<<4) + c;
+ i++;
+ if(i == 2){
+ if(out + 1 > eout)
+ goto exhausted;
+ *out++ = w;
+ w = 0;
+ i = 0;
+ }
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc16(char *out, int lim, uchar *in, int n)
+{
+ uint c;
+ char *eout = out + lim;
+ char *start = out;
+
+ while(n-- > 0){
+ c = *in++;
+ if(out + 2 >= eout)
+ goto exhausted;
+ *out++ = enc16chr(c>>4);
+ *out++ = enc16chr(c&15);
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
--- /dev/null
+++ b/mp/u32.c
@@ -1,0 +1,143 @@
+#include "platform.h"
+
+#define between(x,min,max) (((min-1-x) & (x-max-1))>>8)
+
+int
+enc32chr(int o)
+{
+ int c;
+
+ c = between(o, 0, 25) & ('A'+o);
+ c |= between(o, 26, 31) & ('2'+(o-26));
+ return c;
+}
+
+int
+dec32chr(int c)
+{
+ int o;
+
+ o = between(c, 'A', 'Z') & (1+(c-'A'));
+ o |= between(c, 'a', 'z') & (1+(c-'a'));
+ o |= between(c, '2', '7') & (1+26+(c-'2'));
+ return o-1;
+}
+
+int
+dec32x(uchar *dest, int ndest, char *src, int nsrc, int (*chr)(int))
+{
+ uchar *start;
+ int i, j, u[8];
+
+ if(ndest+1 < (5*nsrc+7)/8)
+ return -1;
+ start = dest;
+ while(nsrc>=8){
+ for(i=0; i<8; i++){
+ j = chr(src[i]);
+ if(j < 0)
+ j = 0;
+ u[i] = j;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ *dest++ = ((0x7 & u[6])<<5) | u[7];
+ src += 8;
+ nsrc -= 8;
+ }
+ if(nsrc > 0){
+ if(nsrc == 1 || nsrc == 3 || nsrc == 6)
+ return -1;
+ for(i=0; i<nsrc; i++){
+ j = chr(src[i]);
+ if(j < 0)
+ j = 0;
+ u[i] = j;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ if(nsrc == 2)
+ goto out;
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ if(nsrc == 4)
+ goto out;
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ if(nsrc == 5)
+ goto out;
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ }
+out:
+ return dest-start;
+}
+
+int
+enc32x(char *dest, int ndest, uchar *src, int nsrc, int (*chr)(int))
+{
+ char *start;
+ int j;
+
+ if(ndest <= (8*nsrc+4)/5)
+ return -1;
+ start = dest;
+ while(nsrc>=5){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = chr(j);
+ j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
+ *dest++ = chr(j);
+ j = (0x1f & (src[1]>>1));
+ *dest++ = chr(j);
+ j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
+ *dest++ = chr(j);
+ j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
+ *dest++ = chr(j);
+ j = (0x1f & (src[3]>>2));
+ *dest++ = chr(j);
+ j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
+ *dest++ = chr(j);
+ j = (0x1f & (src[4]));
+ *dest++ = chr(j);
+ src += 5;
+ nsrc -= 5;
+ }
+ if(nsrc){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = chr(j);
+ j = (0x1c & (src[0]<<2));
+ if(nsrc == 1)
+ goto out;
+ j |= (0x03 & (src[1]>>6));
+ *dest++ = chr(j);
+ j = (0x1f & (src[1]>>1));
+ *dest++ = chr(j);
+ j = (0x10 & (src[1]<<4));
+ if(nsrc == 2)
+ goto out;
+ j |= (0x0f & (src[2]>>4));
+ *dest++ = chr(j);
+ j = (0x1e & (src[2]<<1));
+ if(nsrc == 3)
+ goto out;
+ j |= (0x01 & (src[3]>>7));
+ *dest++ = chr(j);
+ j = (0x1f & (src[3]>>2));
+ *dest++ = chr(j);
+ j = (0x18 & (src[3]<<3));
+out:
+ *dest++ = chr(j);
+ }
+ *dest = 0;
+ return dest-start;
+}
+
+int
+enc32(char *dest, int ndest, uchar *src, int nsrc)
+{
+ return enc32x(dest, ndest, src, nsrc, enc32chr);
+}
+
+int
+dec32(uchar *dest, int ndest, char *src, int nsrc)
+{
+ return dec32x(dest, ndest, src, nsrc, dec32chr);
+}
--- /dev/null
+++ b/mp/u64.c
@@ -1,0 +1,141 @@
+#include "platform.h"
+
+#define between(x,min,max) (((min-1-x) & (x-max-1))>>8)
+
+int
+enc64chr(int o)
+{
+ int c;
+
+ c = between(o, 0, 25) & ('A'+o);
+ c |= between(o, 26, 51) & ('a'+(o-26));
+ c |= between(o, 52, 61) & ('0'+(o-52));
+ c |= between(o, 62, 62) & ('+');
+ c |= between(o, 63, 63) & ('/');
+ return c;
+}
+
+int
+dec64chr(int c)
+{
+ int o;
+
+ o = between(c, 'A', 'Z') & (1+(c-'A'));
+ o |= between(c, 'a', 'z') & (1+26+(c-'a'));
+ o |= between(c, '0', '9') & (1+52+(c-'0'));
+ o |= between(c, '+', '+') & (1+62);
+ o |= between(c, '/', '/') & (1+63);
+ return o-1;
+}
+
+int
+dec64x(uchar *out, int lim, char *in, int n, int (*chr)(int))
+{
+ ulong b24;
+ uchar *start = out;
+ uchar *e = out + lim;
+ int i, c;
+
+ b24 = 0;
+ i = 0;
+ while(n-- > 0){
+ c = chr(*in++);
+ if(c < 0)
+ continue;
+ switch(i){
+ case 0:
+ b24 = c<<18;
+ break;
+ case 1:
+ b24 |= c<<12;
+ break;
+ case 2:
+ b24 |= c<<6;
+ break;
+ case 3:
+ if(out + 3 > e)
+ goto exhausted;
+
+ b24 |= c;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ *out++ = b24;
+ i = 0;
+ continue;
+ }
+ i++;
+ }
+ switch(i){
+ case 2:
+ if(out + 1 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ break;
+ case 3:
+ if(out + 2 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ break;
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc64x(char *out, int lim, uchar *in, int n, int (*chr)(int))
+{
+ int i;
+ ulong b24;
+ char *start = out;
+ char *e = out + lim;
+
+ for(i = n/3; i > 0; i--){
+ b24 = *in++<<16;
+ b24 |= *in++<<8;
+ b24 |= *in++;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = chr(b24>>18);
+ *out++ = chr((b24>>12)&0x3f);
+ *out++ = chr((b24>>6)&0x3f);
+ *out++ = chr(b24&0x3f);
+ }
+
+ switch(n%3){
+ case 2:
+ b24 = *in++<<16;
+ b24 |= *in<<8;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = chr(b24>>18);
+ *out++ = chr((b24>>12)&0x3f);
+ *out++ = chr((b24>>6)&0x3f);
+ *out++ = '=';
+ break;
+ case 1:
+ b24 = *in<<16;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = chr(b24>>18);
+ *out++ = chr((b24>>12)&0x3f);
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
+
+int
+enc64(char *out, int lim, uchar *in, int n)
+{
+ return enc64x(out, lim, in, n, enc64chr);
+}
+
+int
+dec64(uchar *out, int lim, char *in, int n)
+{
+ return dec64x(out, lim, in, n, dec64chr);
+}