|
|
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.