BSD 4_3_Tahoe development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 26 Nov 1983 05:11:09 +0000 (21:11 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 26 Nov 1983 05:11:09 +0000 (21:11 -0800)
Work on file usr/src/ucb/lisp/franz/divbig.c
Work on file usr/tmp/housel/franz/divbig.c

Synthesized-from: CSRG/cd2/4.3tahoe

usr/src/ucb/lisp/franz/divbig.c [new file with mode: 0644]
usr/tmp/housel/franz/divbig.c [new file with mode: 0644]

diff --git a/usr/src/ucb/lisp/franz/divbig.c b/usr/src/ucb/lisp/franz/divbig.c
new file mode 100644 (file)
index 0000000..944304c
--- /dev/null
@@ -0,0 +1,450 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: divbig.c,v 1.4 83/11/26 12:10:16 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 12:22:36 1983 by jkf]-
+ *     divbig.c                                $Locker:  $
+ * bignum division
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+
+#define b 0x40000000
+#define toint(p) ((int) (p))
+
+divbig(dividend, divisor, quotient, remainder)
+lispval dividend, divisor, *quotient, *remainder;
+{
+       register *ujp, *vip;
+       int *alloca(), d, negflag = 0, m, n, carry, rem, qhat, j;
+       int borrow, negrem = 0;
+       long *utop = sp(), *ubot, *vbot, *qbot;
+       register lispval work; lispval export();
+       Keepxs();
+
+       /* copy dividend */
+       for(work = dividend; work; work = work ->s.CDR)
+               stack(work->s.I);
+       ubot = sp();
+       if(*ubot < 0) {         /* knuth's division alg works only for pos
+                                       bignums                         */
+               negflag ^= 1;
+               negrem = 1;
+               dsmult(utop-1,ubot,-1);
+       }
+       stack(0);
+       ubot = sp();
+
+       
+       /*copy divisor */
+       for(work = divisor; work; work = work->s.CDR)
+               stack(work->s.I);
+
+       vbot = sp();
+       stack(0);
+       if(*vbot < 0) {
+               negflag ^= 1;
+               dsmult(ubot-1,vbot,-1);
+       }
+
+       /* check validity of data */
+       n = ubot - vbot;
+       m = utop - ubot - n - 1;
+       if (n == 1) {
+               /* do destructive division by  a single. */
+               rem = dsdiv(utop-1,ubot,*vbot);
+               if(negrem)
+                       rem = -rem;
+               if(negflag)
+                       dsmult(utop-1,ubot,-1);
+               if(remainder)
+                       *remainder = inewint(rem);
+               if(quotient)
+                       *quotient = export(utop,ubot);
+               Freexs();
+               return;
+       }
+       if (m < 0) {
+               if (remainder)
+                       *remainder = dividend;
+               if(quotient)
+                       *quotient = inewint(0);
+               Freexs();
+               return;
+       }
+       qbot = alloca(toint(utop) + toint(vbot) - 2 * toint(ubot));
+d1:
+       d = b /(*vbot +1);
+       dsmult(utop-1,ubot,d);
+       dsmult(ubot-1,vbot,d);
+
+d2:    for(j=0,ujp=ubot; j <= m; j++,ujp++) {
+
+       d3:     
+               qhat = calqhat(ujp,vbot);
+       d4:
+               if((borrow = mlsb(ujp + n, ujp, ubot, -qhat)) < 0) {
+                       adback(ujp + n, ujp, ubot);
+                       qhat--;
+               }
+               qbot[j] = qhat;
+       }
+d8:    if(remainder) {
+               dsdiv(utop-1, utop - n, d);
+               if(negrem) dsmult(utop-1,utop-n,-1);
+               *remainder = export(utop,utop-n);
+       }
+       if(quotient) {
+               if(negflag)
+                       dsmult(qbot+m,qbot,-1);
+               *quotient = export(qbot + m + 1, qbot);
+       }
+       Freexs();
+}
+/*
+ * asm code commented out due to optimizer bug
+ * also, this file is now shared with the 68k version!
+calqhat(ujp,v1p)
+register int *ujp, *v1p;
+{
+asm("  cmpl    (r10),(r11)             # v[1] == u[j] ??");
+asm("  beql    2f                      ");
+asm("  # calculate qhat and rhat simultaneously,");
+asm("  #  qhat in r0");
+asm("  #  rhat in r1");
+asm("  emul    (r11),$0x40000000,4(r11),r4 # u[j]b+u[j+1] into r4,r5");
+asm("  ediv    (r10),r4,r0,r1          # qhat = ((u[j]b+u[j+1])/v[1]) into r0");
+asm("                                  # (u[j]b+u[j+1] -qhat*v[1]) into r1");
+asm("                                  # called rhat");
+asm("1:");
+asm("  # check if v[2]*qhat > rhat*b+u[j+2]");
+asm("  emul    r0,4(r10),$0,r2         # qhat*v[2] into r3,r2");
+asm("  emul    r1,$0x40000000,8(r11),r8 #rhat*b + u[j+2] into r9,r8");
+asm("  # give up if r3,r2 <= r9,r8, otherwise iterate");
+asm("  subl2   r8,r2                   # perform r3,r2 - r9,r8");
+asm("  sbwc    r9,r3");
+asm("  bleq    3f                      # give up if negative or equal");
+asm("  decl    r0                      # otherwise, qhat = qhat - 1");
+asm("  addl2   (r10),r1                # since dec'ed qhat, inc rhat by v[1]");
+asm("  jbr     1b");
+asm("2:        ");
+asm("  # get here if v[1]==u[j]");
+asm("  # set qhat to b-1");
+asm("  # rhat is easily calculated since if we substitute b-1 for qhat in");
+asm("  # the formula, then it simplifies to (u[j+1] + v[1])");
+asm("  # ");
+asm("  addl3   4(r11),(r10),r1         # rhat = u[j+1] + v[1]");
+asm("  movl    $0x3fffffff,r0          # qhat = b-1");
+asm("  jbr     1b");
+asm("3:");
+}
+mlsb(utop,ubot,vtop,nqhat)
+register int *utop, *ubot, *vtop;
+register int nqhat;
+{
+asm("  clrl    r0");
+asm("loop2:    addl2   (r11),r0");
+asm("  emul    r8,-(r9),r0,r2");
+asm("  extzv   $0,$30,r2,(r11)");
+asm("  extv    $30,$32,r2,r0");
+asm("  acbl    r10,$-4,r11,loop2");
+}
+adback(utop,ubot,vtop)
+register int *utop, *ubot, *vtop;
+{
+asm("  clrl    r0");
+asm("loop3:    addl2   -(r9),r0");
+asm("  addl2   (r11),r0");
+asm("  extzv   $0,$30,r0,(r11)");
+asm("  extv    $30,$2,r0,r0");
+asm("  acbl    r10,$-4,r11,loop3");
+}
+dsdiv(top,bot,div)
+register int* bot;
+{
+asm("  clrl    r0");
+asm("loop4:    emul    r0,$0x40000000,(r11),r1");
+asm("  ediv    12(ap),r1,(r11),r0");
+asm("  acbl    4(ap),$4,r11,loop4");
+}
+dsmult(top,bot,mult)
+register int* top;
+{
+asm("  clrl    r0");
+asm("loop5:    emul    12(ap),(r11),r0,r1");
+asm("  extzv   $0,$30,r1,(r11)");
+asm("  extv    $30,$32,r1,r0");
+asm("  acbl    8(ap),$-4,r11,loop5");
+asm("  movl    r1,4(r11)");
+}
+*/
+lispval
+export(top,bot)
+register long *top, *bot;
+{
+       register lispval p;
+       lispval result;
+
+       top--; /* screwey convention matches original
+                 vax assembler convenience */
+       while(bot < top)
+       {
+               if(*bot==0)
+                       bot++;
+               else if(*bot==-1)
+                       *++bot |= 0xc0000000;
+               else break;
+       }
+       if(bot==top) return(inewint(*bot));
+       result = p = newsdot();
+       protect(p);
+       p->s.I = *top--;
+       while(top >= bot) {
+               p = p->s.CDR = newdot();
+               p->s.I = *top--;
+       }
+       p->s.CDR = 0;
+       np--;
+       return(result);
+}
+
+#define MAXINT 0x80000000L
+
+Ihau(fix)
+register int fix;
+{
+       register count;
+       if(fix==MAXINT)
+               return(32);
+       if(fix < 0)
+               fix = -fix;
+       for(count = 0; fix; count++)
+               fix /= 2;
+       return(count);
+}
+lispval
+Lhau()
+{
+       register count;
+       register lispval handy;
+       register dum1,dum2;
+       lispval Labsval();
+
+       handy = lbot->val;
+top:
+       switch(TYPE(handy)) {
+       case INT:
+               count = Ihau(handy->i);
+               break;
+       case SDOT:
+               handy = Labsval();
+               for(count = 0; handy->s.CDR!=((lispval) 0); handy = handy->s.CDR)
+                       count += 30;
+               count += Ihau(handy->s.I);
+               break;
+       default:
+               handy = errorh1(Vermisc,"Haulong: bad argument",nil,
+                              TRUE,997,handy);
+               goto top;
+       }
+       return(inewint(count));
+}
+lispval
+Lhaipar()
+{
+       register lispval work;
+       register n;
+       register int *top = sp() - 1;
+       register int *bot;
+       int mylen;
+
+       /*chkarg(2);*/
+       work = lbot->val;
+                                       /* copy data onto stack */
+on1:
+       switch(TYPE(work)) {
+       case INT:
+               stack(work->i);
+               break;
+       case SDOT:
+               for(; work!=((lispval) 0); work = work->s.CDR)
+                       stack(work->s.I);
+               break;
+       default:
+               work = errorh1(Vermisc,"Haipart: bad first argument",nil,
+                               TRUE,996,work);
+               goto on1;
+       }
+       bot = sp();
+       if(*bot < 0) {
+               stack(0);
+               dsmult(top,bot,-1);
+               bot--;
+       }
+       for(; *bot==0 && bot < top; bot++);
+                               /* recalculate haulong internally */
+       mylen = (top - bot) * 30 + Ihau(*bot);
+                               /* get second argument            */
+       work = lbot[1].val;
+       while(TYPE(work)!=INT)
+               work = errorh1(Vermisc,"Haipart: 2nd arg not int",nil,
+                               TRUE,995,work);
+       n = work->i;
+       if(n >= mylen || -n >= mylen)
+               goto done;
+       if(n==0) return(inewint(0));
+       if(n > 0) {
+                               /* Here we want n most significant bits
+                                  so chop off mylen - n bits */
+               stack(0);
+               n = mylen - n;
+               for(n; n >= 30; n -= 30)
+                       top--;
+               if(top < bot)
+                       error("Internal error in haipart #1",FALSE);
+               dsdiv(top,bot,1<<n);
+
+       } else {
+                               /* here we want abs(n) low order bits */
+               stack(0);
+               bot = top + 1;
+               for(; n <= 0; n += 30)
+                       bot--;
+               n = 30 - n;
+               *bot &= ~ (-1<<n);
+       }
+done:
+       return(export(top + 1,bot));
+}
+#define STICKY 1
+#define TOEVEN 2
+lispval
+Ibiglsh(bignum,count,mode)
+lispval bignum, count;
+{
+       register lispval work;
+       register n;
+       register int *top = sp() - 1;
+       register int *bot;
+       int mylen, guard = 0, sticky = 0, round = 0;
+       lispval export();
+
+                               /* get second argument            */
+       work = count;
+       while(TYPE(work)!=INT)
+               work = errorh1(Vermisc,"Bignum-shift: 2nd arg not int",nil,
+                               TRUE,995,work);
+       n = work->i;
+       if(n==0) return(bignum);
+       for(; n >= 30; n -= 30) {/* Here we want to multiply by 2^n
+                                  so start by copying n/30 zeroes
+                                  onto stack */
+               stack(0);
+       }
+
+       work = bignum;          /* copy data onto stack */
+on1:
+       switch(TYPE(work)) {
+       case INT:
+               stack(work->i);
+               break;
+       case SDOT:
+               for(; work!=((lispval) 0); work = work->s.CDR)
+                       stack(work->s.I);
+               break;
+       default:
+               work = errorh1(Vermisc,"Bignum-shift: bad bignum argument",nil,
+                               TRUE,996,work);
+               goto on1;
+       }
+       bot = sp();
+       if(n >= 0) {
+               stack(0);
+               bot--;
+               dsmult(top,bot,1<<n);
+       } else {
+                       /* Trimming will only work without leading
+                          zeroes without my having to think
+                          a lot harder about it, if the inputs
+                          are canonical */
+               for(n = -n; n > 30; n -= 30) {
+                       if(guard) sticky |= 1;
+                       guard = round;
+                       if(top > bot) {
+                               round = *top;
+                               top --;
+                       } else  {
+                               round = *top;
+                               *top >>= 30;
+                       }
+               }
+               if(n > 0) {
+                       if(guard) sticky |= 1;
+                       guard = round;
+                       round = dsrsh(top,bot,-n,-1<<n);
+               }
+               stack(0); /*so that dsadd1 will work;*/
+               if (mode==STICKY) {
+                       if(((*top&1)==0) && (round | guard | sticky))
+                               dsadd1(top,bot);
+               } else if (mode==TOEVEN) {
+                       int mask;
+
+                       if(n==0) n = 30;
+                       mask = (1<<(n-1));
+                       if(! (round & mask) ) goto chop;
+                       mask -= 1;
+                       if(  ((round&mask)==0)
+                         && guard==0
+                         && sticky==0
+                         && (*top&1)==0 ) goto chop;
+                       dsadd1(top,bot);
+               }
+               chop:;
+       }
+       work = export(top + 1,bot);
+       return(work);
+}
+
+/*From drb  Mon Jul 27 01:25:56 1981
+To: sklower
+
+The idea is that the answer/2
+is equal to the exact answer/2 rounded towards - infinity.  The final bit
+of the answer is the "or" of the true final bit, together with all true
+bits after the binary point.  In other words, the 1's bit of the answer
+is almost always 1.  THE FINAL BIT OF THE ANSWER IS 0 IFF n*2^i = THE
+ANSWER RETURNED EXACTLY, WITH A 0 FINAL BIT.
+
+
+To try again, more succintly:  the answer is correct to within 1, and
+the 1's bit of the answer will be 0 only if the answer is exactly
+correct. */
+
+lispval
+Lsbiglsh()
+{
+       register struct argent *mylbot = lbot;
+       chkarg(2,"sticky-bignum-leftshift");
+       return(Ibiglsh(lbot->val,lbot[1].val,STICKY));
+}
+lispval
+Lbiglsh()
+{
+       register struct argent *mylbot = lbot;
+       chkarg(2,"bignum-leftshift");
+       return(Ibiglsh(lbot->val,lbot[1].val,TOEVEN));
+}
+lispval
+HackHex() /* this is a one minute function so drb and kls can debug biglsh */
+/* (HackHex i) returns a string which is the result of printing i in hex */
+{
+       register struct argent *mylbot = lbot;
+       char buf[32];
+       sprintf(buf,"%lx",lbot->val->i);
+       return((lispval)inewstr(buf));
+}
diff --git a/usr/tmp/housel/franz/divbig.c b/usr/tmp/housel/franz/divbig.c
new file mode 100644 (file)
index 0000000..944304c
--- /dev/null
@@ -0,0 +1,450 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: divbig.c,v 1.4 83/11/26 12:10:16 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 12:22:36 1983 by jkf]-
+ *     divbig.c                                $Locker:  $
+ * bignum division
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+
+#define b 0x40000000
+#define toint(p) ((int) (p))
+
+divbig(dividend, divisor, quotient, remainder)
+lispval dividend, divisor, *quotient, *remainder;
+{
+       register *ujp, *vip;
+       int *alloca(), d, negflag = 0, m, n, carry, rem, qhat, j;
+       int borrow, negrem = 0;
+       long *utop = sp(), *ubot, *vbot, *qbot;
+       register lispval work; lispval export();
+       Keepxs();
+
+       /* copy dividend */
+       for(work = dividend; work; work = work ->s.CDR)
+               stack(work->s.I);
+       ubot = sp();
+       if(*ubot < 0) {         /* knuth's division alg works only for pos
+                                       bignums                         */
+               negflag ^= 1;
+               negrem = 1;
+               dsmult(utop-1,ubot,-1);
+       }
+       stack(0);
+       ubot = sp();
+
+       
+       /*copy divisor */
+       for(work = divisor; work; work = work->s.CDR)
+               stack(work->s.I);
+
+       vbot = sp();
+       stack(0);
+       if(*vbot < 0) {
+               negflag ^= 1;
+               dsmult(ubot-1,vbot,-1);
+       }
+
+       /* check validity of data */
+       n = ubot - vbot;
+       m = utop - ubot - n - 1;
+       if (n == 1) {
+               /* do destructive division by  a single. */
+               rem = dsdiv(utop-1,ubot,*vbot);
+               if(negrem)
+                       rem = -rem;
+               if(negflag)
+                       dsmult(utop-1,ubot,-1);
+               if(remainder)
+                       *remainder = inewint(rem);
+               if(quotient)
+                       *quotient = export(utop,ubot);
+               Freexs();
+               return;
+       }
+       if (m < 0) {
+               if (remainder)
+                       *remainder = dividend;
+               if(quotient)
+                       *quotient = inewint(0);
+               Freexs();
+               return;
+       }
+       qbot = alloca(toint(utop) + toint(vbot) - 2 * toint(ubot));
+d1:
+       d = b /(*vbot +1);
+       dsmult(utop-1,ubot,d);
+       dsmult(ubot-1,vbot,d);
+
+d2:    for(j=0,ujp=ubot; j <= m; j++,ujp++) {
+
+       d3:     
+               qhat = calqhat(ujp,vbot);
+       d4:
+               if((borrow = mlsb(ujp + n, ujp, ubot, -qhat)) < 0) {
+                       adback(ujp + n, ujp, ubot);
+                       qhat--;
+               }
+               qbot[j] = qhat;
+       }
+d8:    if(remainder) {
+               dsdiv(utop-1, utop - n, d);
+               if(negrem) dsmult(utop-1,utop-n,-1);
+               *remainder = export(utop,utop-n);
+       }
+       if(quotient) {
+               if(negflag)
+                       dsmult(qbot+m,qbot,-1);
+               *quotient = export(qbot + m + 1, qbot);
+       }
+       Freexs();
+}
+/*
+ * asm code commented out due to optimizer bug
+ * also, this file is now shared with the 68k version!
+calqhat(ujp,v1p)
+register int *ujp, *v1p;
+{
+asm("  cmpl    (r10),(r11)             # v[1] == u[j] ??");
+asm("  beql    2f                      ");
+asm("  # calculate qhat and rhat simultaneously,");
+asm("  #  qhat in r0");
+asm("  #  rhat in r1");
+asm("  emul    (r11),$0x40000000,4(r11),r4 # u[j]b+u[j+1] into r4,r5");
+asm("  ediv    (r10),r4,r0,r1          # qhat = ((u[j]b+u[j+1])/v[1]) into r0");
+asm("                                  # (u[j]b+u[j+1] -qhat*v[1]) into r1");
+asm("                                  # called rhat");
+asm("1:");
+asm("  # check if v[2]*qhat > rhat*b+u[j+2]");
+asm("  emul    r0,4(r10),$0,r2         # qhat*v[2] into r3,r2");
+asm("  emul    r1,$0x40000000,8(r11),r8 #rhat*b + u[j+2] into r9,r8");
+asm("  # give up if r3,r2 <= r9,r8, otherwise iterate");
+asm("  subl2   r8,r2                   # perform r3,r2 - r9,r8");
+asm("  sbwc    r9,r3");
+asm("  bleq    3f                      # give up if negative or equal");
+asm("  decl    r0                      # otherwise, qhat = qhat - 1");
+asm("  addl2   (r10),r1                # since dec'ed qhat, inc rhat by v[1]");
+asm("  jbr     1b");
+asm("2:        ");
+asm("  # get here if v[1]==u[j]");
+asm("  # set qhat to b-1");
+asm("  # rhat is easily calculated since if we substitute b-1 for qhat in");
+asm("  # the formula, then it simplifies to (u[j+1] + v[1])");
+asm("  # ");
+asm("  addl3   4(r11),(r10),r1         # rhat = u[j+1] + v[1]");
+asm("  movl    $0x3fffffff,r0          # qhat = b-1");
+asm("  jbr     1b");
+asm("3:");
+}
+mlsb(utop,ubot,vtop,nqhat)
+register int *utop, *ubot, *vtop;
+register int nqhat;
+{
+asm("  clrl    r0");
+asm("loop2:    addl2   (r11),r0");
+asm("  emul    r8,-(r9),r0,r2");
+asm("  extzv   $0,$30,r2,(r11)");
+asm("  extv    $30,$32,r2,r0");
+asm("  acbl    r10,$-4,r11,loop2");
+}
+adback(utop,ubot,vtop)
+register int *utop, *ubot, *vtop;
+{
+asm("  clrl    r0");
+asm("loop3:    addl2   -(r9),r0");
+asm("  addl2   (r11),r0");
+asm("  extzv   $0,$30,r0,(r11)");
+asm("  extv    $30,$2,r0,r0");
+asm("  acbl    r10,$-4,r11,loop3");
+}
+dsdiv(top,bot,div)
+register int* bot;
+{
+asm("  clrl    r0");
+asm("loop4:    emul    r0,$0x40000000,(r11),r1");
+asm("  ediv    12(ap),r1,(r11),r0");
+asm("  acbl    4(ap),$4,r11,loop4");
+}
+dsmult(top,bot,mult)
+register int* top;
+{
+asm("  clrl    r0");
+asm("loop5:    emul    12(ap),(r11),r0,r1");
+asm("  extzv   $0,$30,r1,(r11)");
+asm("  extv    $30,$32,r1,r0");
+asm("  acbl    8(ap),$-4,r11,loop5");
+asm("  movl    r1,4(r11)");
+}
+*/
+lispval
+export(top,bot)
+register long *top, *bot;
+{
+       register lispval p;
+       lispval result;
+
+       top--; /* screwey convention matches original
+                 vax assembler convenience */
+       while(bot < top)
+       {
+               if(*bot==0)
+                       bot++;
+               else if(*bot==-1)
+                       *++bot |= 0xc0000000;
+               else break;
+       }
+       if(bot==top) return(inewint(*bot));
+       result = p = newsdot();
+       protect(p);
+       p->s.I = *top--;
+       while(top >= bot) {
+               p = p->s.CDR = newdot();
+               p->s.I = *top--;
+       }
+       p->s.CDR = 0;
+       np--;
+       return(result);
+}
+
+#define MAXINT 0x80000000L
+
+Ihau(fix)
+register int fix;
+{
+       register count;
+       if(fix==MAXINT)
+               return(32);
+       if(fix < 0)
+               fix = -fix;
+       for(count = 0; fix; count++)
+               fix /= 2;
+       return(count);
+}
+lispval
+Lhau()
+{
+       register count;
+       register lispval handy;
+       register dum1,dum2;
+       lispval Labsval();
+
+       handy = lbot->val;
+top:
+       switch(TYPE(handy)) {
+       case INT:
+               count = Ihau(handy->i);
+               break;
+       case SDOT:
+               handy = Labsval();
+               for(count = 0; handy->s.CDR!=((lispval) 0); handy = handy->s.CDR)
+                       count += 30;
+               count += Ihau(handy->s.I);
+               break;
+       default:
+               handy = errorh1(Vermisc,"Haulong: bad argument",nil,
+                              TRUE,997,handy);
+               goto top;
+       }
+       return(inewint(count));
+}
+lispval
+Lhaipar()
+{
+       register lispval work;
+       register n;
+       register int *top = sp() - 1;
+       register int *bot;
+       int mylen;
+
+       /*chkarg(2);*/
+       work = lbot->val;
+                                       /* copy data onto stack */
+on1:
+       switch(TYPE(work)) {
+       case INT:
+               stack(work->i);
+               break;
+       case SDOT:
+               for(; work!=((lispval) 0); work = work->s.CDR)
+                       stack(work->s.I);
+               break;
+       default:
+               work = errorh1(Vermisc,"Haipart: bad first argument",nil,
+                               TRUE,996,work);
+               goto on1;
+       }
+       bot = sp();
+       if(*bot < 0) {
+               stack(0);
+               dsmult(top,bot,-1);
+               bot--;
+       }
+       for(; *bot==0 && bot < top; bot++);
+                               /* recalculate haulong internally */
+       mylen = (top - bot) * 30 + Ihau(*bot);
+                               /* get second argument            */
+       work = lbot[1].val;
+       while(TYPE(work)!=INT)
+               work = errorh1(Vermisc,"Haipart: 2nd arg not int",nil,
+                               TRUE,995,work);
+       n = work->i;
+       if(n >= mylen || -n >= mylen)
+               goto done;
+       if(n==0) return(inewint(0));
+       if(n > 0) {
+                               /* Here we want n most significant bits
+                                  so chop off mylen - n bits */
+               stack(0);
+               n = mylen - n;
+               for(n; n >= 30; n -= 30)
+                       top--;
+               if(top < bot)
+                       error("Internal error in haipart #1",FALSE);
+               dsdiv(top,bot,1<<n);
+
+       } else {
+                               /* here we want abs(n) low order bits */
+               stack(0);
+               bot = top + 1;
+               for(; n <= 0; n += 30)
+                       bot--;
+               n = 30 - n;
+               *bot &= ~ (-1<<n);
+       }
+done:
+       return(export(top + 1,bot));
+}
+#define STICKY 1
+#define TOEVEN 2
+lispval
+Ibiglsh(bignum,count,mode)
+lispval bignum, count;
+{
+       register lispval work;
+       register n;
+       register int *top = sp() - 1;
+       register int *bot;
+       int mylen, guard = 0, sticky = 0, round = 0;
+       lispval export();
+
+                               /* get second argument            */
+       work = count;
+       while(TYPE(work)!=INT)
+               work = errorh1(Vermisc,"Bignum-shift: 2nd arg not int",nil,
+                               TRUE,995,work);
+       n = work->i;
+       if(n==0) return(bignum);
+       for(; n >= 30; n -= 30) {/* Here we want to multiply by 2^n
+                                  so start by copying n/30 zeroes
+                                  onto stack */
+               stack(0);
+       }
+
+       work = bignum;          /* copy data onto stack */
+on1:
+       switch(TYPE(work)) {
+       case INT:
+               stack(work->i);
+               break;
+       case SDOT:
+               for(; work!=((lispval) 0); work = work->s.CDR)
+                       stack(work->s.I);
+               break;
+       default:
+               work = errorh1(Vermisc,"Bignum-shift: bad bignum argument",nil,
+                               TRUE,996,work);
+               goto on1;
+       }
+       bot = sp();
+       if(n >= 0) {
+               stack(0);
+               bot--;
+               dsmult(top,bot,1<<n);
+       } else {
+                       /* Trimming will only work without leading
+                          zeroes without my having to think
+                          a lot harder about it, if the inputs
+                          are canonical */
+               for(n = -n; n > 30; n -= 30) {
+                       if(guard) sticky |= 1;
+                       guard = round;
+                       if(top > bot) {
+                               round = *top;
+                               top --;
+                       } else  {
+                               round = *top;
+                               *top >>= 30;
+                       }
+               }
+               if(n > 0) {
+                       if(guard) sticky |= 1;
+                       guard = round;
+                       round = dsrsh(top,bot,-n,-1<<n);
+               }
+               stack(0); /*so that dsadd1 will work;*/
+               if (mode==STICKY) {
+                       if(((*top&1)==0) && (round | guard | sticky))
+                               dsadd1(top,bot);
+               } else if (mode==TOEVEN) {
+                       int mask;
+
+                       if(n==0) n = 30;
+                       mask = (1<<(n-1));
+                       if(! (round & mask) ) goto chop;
+                       mask -= 1;
+                       if(  ((round&mask)==0)
+                         && guard==0
+                         && sticky==0
+                         && (*top&1)==0 ) goto chop;
+                       dsadd1(top,bot);
+               }
+               chop:;
+       }
+       work = export(top + 1,bot);
+       return(work);
+}
+
+/*From drb  Mon Jul 27 01:25:56 1981
+To: sklower
+
+The idea is that the answer/2
+is equal to the exact answer/2 rounded towards - infinity.  The final bit
+of the answer is the "or" of the true final bit, together with all true
+bits after the binary point.  In other words, the 1's bit of the answer
+is almost always 1.  THE FINAL BIT OF THE ANSWER IS 0 IFF n*2^i = THE
+ANSWER RETURNED EXACTLY, WITH A 0 FINAL BIT.
+
+
+To try again, more succintly:  the answer is correct to within 1, and
+the 1's bit of the answer will be 0 only if the answer is exactly
+correct. */
+
+lispval
+Lsbiglsh()
+{
+       register struct argent *mylbot = lbot;
+       chkarg(2,"sticky-bignum-leftshift");
+       return(Ibiglsh(lbot->val,lbot[1].val,STICKY));
+}
+lispval
+Lbiglsh()
+{
+       register struct argent *mylbot = lbot;
+       chkarg(2,"bignum-leftshift");
+       return(Ibiglsh(lbot->val,lbot[1].val,TOEVEN));
+}
+lispval
+HackHex() /* this is a one minute function so drb and kls can debug biglsh */
+/* (HackHex i) returns a string which is the result of printing i in hex */
+{
+       register struct argent *mylbot = lbot;
+       char buf[32];
+       sprintf(buf,"%lx",lbot->val->i);
+       return((lispval)inewstr(buf));
+}