|
|
1.1 ! root 1: #ifndef lint ! 2: static char *rcsid = ! 3: "$Header: divbig.c,v 1.3 83/09/12 14:17:07 sklower Exp $"; ! 4: #endif ! 5: ! 6: /* -[Sat Jan 29 12:22:36 1983 by jkf]- ! 7: * divbig.c $Locker: $ ! 8: * bignum division ! 9: * ! 10: * (c) copyright 1982, Regents of the University of California ! 11: */ ! 12: ! 13: ! 14: #include "global.h" ! 15: ! 16: #define b 0x40000000 ! 17: #define toint(p) ((int) (p)) ! 18: ! 19: divbig(dividend, divisor, quotient, remainder) ! 20: lispval dividend, divisor, *quotient, *remainder; ! 21: { ! 22: register *ujp, *vip; ! 23: int *alloca(), d, negflag = 0, m, n, carry, rem, qhat, j; ! 24: int borrow, negrem = 0; ! 25: long *utop = sp(), *ubot, *vbot, *qbot; ! 26: register lispval work; lispval export(); ! 27: Keepxs(); ! 28: ! 29: /* copy dividend */ ! 30: for(work = dividend; work; work = work ->s.CDR) ! 31: stack(work->s.I); ! 32: ubot = sp(); ! 33: if(*ubot < 0) { /* knuth's division alg works only for pos ! 34: bignums */ ! 35: negflag ^= 1; ! 36: negrem = 1; ! 37: dsmult(utop-1,ubot,-1); ! 38: } ! 39: stack(0); ! 40: ubot = sp(); ! 41: ! 42: ! 43: /*copy divisor */ ! 44: for(work = divisor; work; work = work->s.CDR) ! 45: stack(work->s.I); ! 46: ! 47: vbot = sp(); ! 48: stack(0); ! 49: if(*vbot < 0) { ! 50: negflag ^= 1; ! 51: dsmult(ubot-1,vbot,-1); ! 52: } ! 53: ! 54: /* check validity of data */ ! 55: n = ubot - vbot; ! 56: m = utop - ubot - n - 1; ! 57: if (n == 1) { ! 58: /* do destructive division by a single. */ ! 59: rem = dsdiv(utop-1,ubot,*vbot); ! 60: if(negrem) ! 61: rem = -rem; ! 62: if(negflag) ! 63: dsmult(utop-1,ubot,-1); ! 64: if(remainder) ! 65: *remainder = inewint(rem); ! 66: if(quotient) ! 67: *quotient = export(utop,ubot); ! 68: Freexs(); ! 69: return; ! 70: } ! 71: if (m < 0) { ! 72: if (remainder) ! 73: *remainder = dividend; ! 74: if(quotient) ! 75: *quotient = inewint(0); ! 76: Freexs(); ! 77: return; ! 78: } ! 79: qbot = alloca(toint(utop) + toint(vbot) - 2 * toint(ubot)); ! 80: d1: ! 81: d = b /(*vbot +1); ! 82: dsmult(utop-1,ubot,d); ! 83: dsmult(ubot-1,vbot,d); ! 84: ! 85: d2: for(j=0,ujp=ubot; j <= m; j++,ujp++) { ! 86: ! 87: d3: ! 88: qhat = calqhat(ujp,vbot); ! 89: d4: ! 90: if((borrow = mlsb(ujp + n, ujp, ubot, -qhat)) < 0) { ! 91: adback(ujp + n, ujp, ubot); ! 92: qhat--; ! 93: } ! 94: qbot[j] = qhat; ! 95: } ! 96: d8: if(remainder) { ! 97: dsdiv(utop-1, utop - n, d); ! 98: if(negrem) dsmult(utop-1,utop-n,-1); ! 99: *remainder = export(utop,utop-n); ! 100: } ! 101: if(quotient) { ! 102: if(negflag) ! 103: dsmult(qbot+m,qbot,-1); ! 104: *quotient = export(qbot + m + 1, qbot); ! 105: } ! 106: Freexs(); ! 107: } ! 108: /* ! 109: * asm code commented out due to optimizer bug ! 110: * also, this file is now shared with the 68k version! ! 111: calqhat(ujp,v1p) ! 112: register int *ujp, *v1p; ! 113: { ! 114: asm(" cmpl (r10),(r11) # v[1] == u[j] ??"); ! 115: asm(" beql 2f "); ! 116: asm(" # calculate qhat and rhat simultaneously,"); ! 117: asm(" # qhat in r0"); ! 118: asm(" # rhat in r1"); ! 119: asm(" emul (r11),$0x40000000,4(r11),r4 # u[j]b+u[j+1] into r4,r5"); ! 120: asm(" ediv (r10),r4,r0,r1 # qhat = ((u[j]b+u[j+1])/v[1]) into r0"); ! 121: asm(" # (u[j]b+u[j+1] -qhat*v[1]) into r1"); ! 122: asm(" # called rhat"); ! 123: asm("1:"); ! 124: asm(" # check if v[2]*qhat > rhat*b+u[j+2]"); ! 125: asm(" emul r0,4(r10),$0,r2 # qhat*v[2] into r3,r2"); ! 126: asm(" emul r1,$0x40000000,8(r11),r8 #rhat*b + u[j+2] into r9,r8"); ! 127: asm(" # give up if r3,r2 <= r9,r8, otherwise iterate"); ! 128: asm(" subl2 r8,r2 # perform r3,r2 - r9,r8"); ! 129: asm(" sbwc r9,r3"); ! 130: asm(" bleq 3f # give up if negative or equal"); ! 131: asm(" decl r0 # otherwise, qhat = qhat - 1"); ! 132: asm(" addl2 (r10),r1 # since dec'ed qhat, inc rhat by v[1]"); ! 133: asm(" jbr 1b"); ! 134: asm("2: "); ! 135: asm(" # get here if v[1]==u[j]"); ! 136: asm(" # set qhat to b-1"); ! 137: asm(" # rhat is easily calculated since if we substitute b-1 for qhat in"); ! 138: asm(" # the formula, then it simplifies to (u[j+1] + v[1])"); ! 139: asm(" # "); ! 140: asm(" addl3 4(r11),(r10),r1 # rhat = u[j+1] + v[1]"); ! 141: asm(" movl $0x3fffffff,r0 # qhat = b-1"); ! 142: asm(" jbr 1b"); ! 143: asm("3:"); ! 144: } ! 145: mlsb(utop,ubot,vtop,nqhat) ! 146: register int *utop, *ubot, *vtop; ! 147: register int nqhat; ! 148: { ! 149: asm(" clrl r0"); ! 150: asm("loop2: addl2 (r11),r0"); ! 151: asm(" emul r8,-(r9),r0,r2"); ! 152: asm(" extzv $0,$30,r2,(r11)"); ! 153: asm(" extv $30,$32,r2,r0"); ! 154: asm(" acbl r10,$-4,r11,loop2"); ! 155: } ! 156: adback(utop,ubot,vtop) ! 157: register int *utop, *ubot, *vtop; ! 158: { ! 159: asm(" clrl r0"); ! 160: asm("loop3: addl2 -(r9),r0"); ! 161: asm(" addl2 (r11),r0"); ! 162: asm(" extzv $0,$30,r0,(r11)"); ! 163: asm(" extv $30,$2,r0,r0"); ! 164: asm(" acbl r10,$-4,r11,loop3"); ! 165: } ! 166: dsdiv(top,bot,div) ! 167: register int* bot; ! 168: { ! 169: asm(" clrl r0"); ! 170: asm("loop4: emul r0,$0x40000000,(r11),r1"); ! 171: asm(" ediv 12(ap),r1,(r11),r0"); ! 172: asm(" acbl 4(ap),$4,r11,loop4"); ! 173: } ! 174: dsmult(top,bot,mult) ! 175: register int* top; ! 176: { ! 177: asm(" clrl r0"); ! 178: asm("loop5: emul 12(ap),(r11),r0,r1"); ! 179: asm(" extzv $0,$30,r1,(r11)"); ! 180: asm(" extv $30,$32,r1,r0"); ! 181: asm(" acbl 8(ap),$-4,r11,loop5"); ! 182: asm(" movl r1,4(r11)"); ! 183: } ! 184: */ ! 185: lispval ! 186: export(top,bot) ! 187: register long *top, *bot; ! 188: { ! 189: register lispval p; ! 190: lispval result; ! 191: ! 192: top--; /* screwey convention matches original ! 193: vax assembler convenience */ ! 194: while(bot < top) ! 195: { ! 196: if(*bot==0) ! 197: bot++; ! 198: else if(*bot==-1) ! 199: *++bot |= 0xc0000000; ! 200: else break; ! 201: } ! 202: if(bot==top) return(inewint(*bot)); ! 203: result = p = newsdot(); ! 204: protect(p); ! 205: p->s.I = *top--; ! 206: while(top >= bot) { ! 207: p = p->s.CDR = newdot(); ! 208: p->s.I = *top--; ! 209: } ! 210: p->s.CDR = 0; ! 211: np--; ! 212: return(result); ! 213: } ! 214: ! 215: #define MAXINT 0x80000000L ! 216: ! 217: Ihau(fix) ! 218: register int fix; ! 219: { ! 220: register count; ! 221: if(fix==MAXINT) ! 222: return(32); ! 223: if(fix < 0) ! 224: fix = -fix; ! 225: for(count = 0; fix; count++) ! 226: fix /= 2; ! 227: return(count); ! 228: } ! 229: lispval ! 230: Lhau() ! 231: { ! 232: register count; ! 233: register lispval handy; ! 234: register dum1,dum2; ! 235: lispval Labsval(); ! 236: ! 237: handy = lbot->val; ! 238: top: ! 239: switch(TYPE(handy)) { ! 240: case INT: ! 241: count = Ihau(handy->i); ! 242: break; ! 243: case SDOT: ! 244: handy = Labsval(); ! 245: for(count = 0; handy->s.CDR!=((lispval) 0); handy = handy->s.CDR) ! 246: count += 30; ! 247: count += Ihau(handy->s.I); ! 248: break; ! 249: default: ! 250: handy = errorh1(Vermisc,"Haulong: bad argument",nil, ! 251: TRUE,997,handy); ! 252: goto top; ! 253: } ! 254: return(inewint(count)); ! 255: } ! 256: lispval ! 257: Lhaipar() ! 258: { ! 259: int *sp(); ! 260: register lispval work; ! 261: register n; ! 262: register int *top = sp() - 1; ! 263: register int *bot; ! 264: int mylen; ! 265: ! 266: /*chkarg(2);*/ ! 267: work = lbot->val; ! 268: /* copy data onto stack */ ! 269: on1: ! 270: switch(TYPE(work)) { ! 271: case INT: ! 272: stack(work->i); ! 273: break; ! 274: case SDOT: ! 275: for(; work!=((lispval) 0); work = work->s.CDR) ! 276: stack(work->s.I); ! 277: break; ! 278: default: ! 279: work = errorh1(Vermisc,"Haipart: bad first argument",nil, ! 280: TRUE,996,work); ! 281: goto on1; ! 282: } ! 283: bot = sp(); ! 284: if(*bot < 0) { ! 285: stack(0); ! 286: dsmult(top,bot,-1); ! 287: bot--; ! 288: } ! 289: for(; *bot==0 && bot < top; bot++); ! 290: /* recalculate haulong internally */ ! 291: mylen = (top - bot) * 30 + Ihau(*bot); ! 292: /* get second argument */ ! 293: work = lbot[1].val; ! 294: while(TYPE(work)!=INT) ! 295: work = errorh1(Vermisc,"Haipart: 2nd arg not int",nil, ! 296: TRUE,995,work); ! 297: n = work->i; ! 298: if(n >= mylen || -n >= mylen) ! 299: goto done; ! 300: if(n==0) return(inewint(0)); ! 301: if(n > 0) { ! 302: /* Here we want n most significant bits ! 303: so chop off mylen - n bits */ ! 304: stack(0); ! 305: n = mylen - n; ! 306: for(n; n >= 30; n -= 30) ! 307: top--; ! 308: if(top < bot) ! 309: error("Internal error in haipart #1",FALSE); ! 310: dsdiv(top,bot,1<<n); ! 311: ! 312: } else { ! 313: /* here we want abs(n) low order bits */ ! 314: stack(0); ! 315: bot = top + 1; ! 316: for(; n <= 0; n += 30) ! 317: bot--; ! 318: n = 30 - n; ! 319: *bot &= ~ (-1<<n); ! 320: } ! 321: done: ! 322: return(export(top + 1,bot)); ! 323: } ! 324: #define STICKY 1 ! 325: #define TOEVEN 2 ! 326: lispval ! 327: Ibiglsh(bignum,count,mode) ! 328: lispval bignum, count; ! 329: { ! 330: int *sp(); ! 331: register lispval work; ! 332: register n; ! 333: register int *top = sp() - 1; ! 334: register int *bot; ! 335: int mylen, guard = 0, sticky = 0, round = 0; ! 336: lispval export(); ! 337: ! 338: /* get second argument */ ! 339: work = count; ! 340: while(TYPE(work)!=INT) ! 341: work = errorh1(Vermisc,"Bignum-shift: 2nd arg not int",nil, ! 342: TRUE,995,work); ! 343: n = work->i; ! 344: if(n==0) return(bignum); ! 345: for(; n >= 30; n -= 30) {/* Here we want to multiply by 2^n ! 346: so start by copying n/30 zeroes ! 347: onto stack */ ! 348: stack(0); ! 349: } ! 350: ! 351: work = bignum; /* copy data onto stack */ ! 352: on1: ! 353: switch(TYPE(work)) { ! 354: case INT: ! 355: stack(work->i); ! 356: break; ! 357: case SDOT: ! 358: for(; work!=((lispval) 0); work = work->s.CDR) ! 359: stack(work->s.I); ! 360: break; ! 361: default: ! 362: work = errorh1(Vermisc,"Bignum-shift: bad bignum argument",nil, ! 363: TRUE,996,work); ! 364: goto on1; ! 365: } ! 366: bot = sp(); ! 367: if(n >= 0) { ! 368: stack(0); ! 369: bot--; ! 370: dsmult(top,bot,1<<n); ! 371: } else { ! 372: /* Trimming will only work without leading ! 373: zeroes without my having to think ! 374: a lot harder about it, if the inputs ! 375: are canonical */ ! 376: for(n = -n; n > 30; n -= 30) { ! 377: if(guard) sticky |= 1; ! 378: guard = round; ! 379: if(top > bot) { ! 380: round = *top; ! 381: top --; ! 382: } else { ! 383: round = *top; ! 384: *top >>= 30; ! 385: } ! 386: } ! 387: if(n > 0) { ! 388: if(guard) sticky |= 1; ! 389: guard = round; ! 390: round = dsrsh(top,bot,-n,-1<<n); ! 391: } ! 392: stack(0); /*so that dsadd1 will work;*/ ! 393: if (mode==STICKY) { ! 394: if(((*top&1)==0) && (round | guard | sticky)) ! 395: dsadd1(top,bot); ! 396: } else if (mode==TOEVEN) { ! 397: int mask; ! 398: ! 399: if(n==0) n = 30; ! 400: mask = (1<<(n-1)); ! 401: if(! (round & mask) ) goto chop; ! 402: mask -= 1; ! 403: if( ((round&mask)==0) ! 404: && guard==0 ! 405: && sticky==0 ! 406: && (*top&1)==0 ) goto chop; ! 407: dsadd1(top,bot); ! 408: } ! 409: chop:; ! 410: } ! 411: work = export(top + 1,bot); ! 412: return(work); ! 413: } ! 414: ! 415: /*From drb Mon Jul 27 01:25:56 1981 ! 416: To: sklower ! 417: ! 418: The idea is that the answer/2 ! 419: is equal to the exact answer/2 rounded towards - infinity. The final bit ! 420: of the answer is the "or" of the true final bit, together with all true ! 421: bits after the binary point. In other words, the 1's bit of the answer ! 422: is almost always 1. THE FINAL BIT OF THE ANSWER IS 0 IFF n*2^i = THE ! 423: ANSWER RETURNED EXACTLY, WITH A 0 FINAL BIT. ! 424: ! 425: ! 426: To try again, more succintly: the answer is correct to within 1, and ! 427: the 1's bit of the answer will be 0 only if the answer is exactly ! 428: correct. */ ! 429: ! 430: lispval ! 431: Lsbiglsh() ! 432: { ! 433: register struct argent *mylbot = lbot; ! 434: chkarg(2,"sticky-bignum-leftshift"); ! 435: return(Ibiglsh(lbot->val,lbot[1].val,STICKY)); ! 436: } ! 437: lispval ! 438: Lbiglsh() ! 439: { ! 440: register struct argent *mylbot = lbot; ! 441: chkarg(2,"bignum-leftshift"); ! 442: return(Ibiglsh(lbot->val,lbot[1].val,TOEVEN)); ! 443: } ! 444: lispval ! 445: HackHex() /* this is a one minute function so drb and kls can debug biglsh */ ! 446: /* (HackHex i) returns a string which is the result of printing i in hex */ ! 447: { ! 448: register struct argent *mylbot = lbot; ! 449: char buf[32]; ! 450: sprintf(buf,"%lx",lbot->val->i); ! 451: return((lispval)inewstr(buf)); ! 452: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.