|
|
1.1 root 1: #ifndef lint
2: static char *rcsid =
3: "$Header: divbig.c,v 1.4 83/11/26 12:10:16 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: register lispval work;
260: register n;
261: register int *top = sp() - 1;
262: register int *bot;
263: int mylen;
264:
265: /*chkarg(2);*/
266: work = lbot->val;
267: /* copy data onto stack */
268: on1:
269: switch(TYPE(work)) {
270: case INT:
271: stack(work->i);
272: break;
273: case SDOT:
274: for(; work!=((lispval) 0); work = work->s.CDR)
275: stack(work->s.I);
276: break;
277: default:
278: work = errorh1(Vermisc,"Haipart: bad first argument",nil,
279: TRUE,996,work);
280: goto on1;
281: }
282: bot = sp();
283: if(*bot < 0) {
284: stack(0);
285: dsmult(top,bot,-1);
286: bot--;
287: }
288: for(; *bot==0 && bot < top; bot++);
289: /* recalculate haulong internally */
290: mylen = (top - bot) * 30 + Ihau(*bot);
291: /* get second argument */
292: work = lbot[1].val;
293: while(TYPE(work)!=INT)
294: work = errorh1(Vermisc,"Haipart: 2nd arg not int",nil,
295: TRUE,995,work);
296: n = work->i;
297: if(n >= mylen || -n >= mylen)
298: goto done;
299: if(n==0) return(inewint(0));
300: if(n > 0) {
301: /* Here we want n most significant bits
302: so chop off mylen - n bits */
303: stack(0);
304: n = mylen - n;
305: for(n; n >= 30; n -= 30)
306: top--;
307: if(top < bot)
308: error("Internal error in haipart #1",FALSE);
309: dsdiv(top,bot,1<<n);
310:
311: } else {
312: /* here we want abs(n) low order bits */
313: stack(0);
314: bot = top + 1;
315: for(; n <= 0; n += 30)
316: bot--;
317: n = 30 - n;
318: *bot &= ~ (-1<<n);
319: }
320: done:
321: return(export(top + 1,bot));
322: }
323: #define STICKY 1
324: #define TOEVEN 2
325: lispval
326: Ibiglsh(bignum,count,mode)
327: lispval bignum, count;
328: {
329: register lispval work;
330: register n;
331: register int *top = sp() - 1;
332: register int *bot;
333: int mylen, guard = 0, sticky = 0, round = 0;
334: lispval export();
335:
336: /* get second argument */
337: work = count;
338: while(TYPE(work)!=INT)
339: work = errorh1(Vermisc,"Bignum-shift: 2nd arg not int",nil,
340: TRUE,995,work);
341: n = work->i;
342: if(n==0) return(bignum);
343: for(; n >= 30; n -= 30) {/* Here we want to multiply by 2^n
344: so start by copying n/30 zeroes
345: onto stack */
346: stack(0);
347: }
348:
349: work = bignum; /* copy data onto stack */
350: on1:
351: switch(TYPE(work)) {
352: case INT:
353: stack(work->i);
354: break;
355: case SDOT:
356: for(; work!=((lispval) 0); work = work->s.CDR)
357: stack(work->s.I);
358: break;
359: default:
360: work = errorh1(Vermisc,"Bignum-shift: bad bignum argument",nil,
361: TRUE,996,work);
362: goto on1;
363: }
364: bot = sp();
365: if(n >= 0) {
366: stack(0);
367: bot--;
368: dsmult(top,bot,1<<n);
369: } else {
370: /* Trimming will only work without leading
371: zeroes without my having to think
372: a lot harder about it, if the inputs
373: are canonical */
374: for(n = -n; n > 30; n -= 30) {
375: if(guard) sticky |= 1;
376: guard = round;
377: if(top > bot) {
378: round = *top;
379: top --;
380: } else {
381: round = *top;
382: *top >>= 30;
383: }
384: }
385: if(n > 0) {
386: if(guard) sticky |= 1;
387: guard = round;
388: round = dsrsh(top,bot,-n,-1<<n);
389: }
390: stack(0); /*so that dsadd1 will work;*/
391: if (mode==STICKY) {
392: if(((*top&1)==0) && (round | guard | sticky))
393: dsadd1(top,bot);
394: } else if (mode==TOEVEN) {
395: int mask;
396:
397: if(n==0) n = 30;
398: mask = (1<<(n-1));
399: if(! (round & mask) ) goto chop;
400: mask -= 1;
401: if( ((round&mask)==0)
402: && guard==0
403: && sticky==0
404: && (*top&1)==0 ) goto chop;
405: dsadd1(top,bot);
406: }
407: chop:;
408: }
409: work = export(top + 1,bot);
410: return(work);
411: }
412:
413: /*From drb Mon Jul 27 01:25:56 1981
414: To: sklower
415:
416: The idea is that the answer/2
417: is equal to the exact answer/2 rounded towards - infinity. The final bit
418: of the answer is the "or" of the true final bit, together with all true
419: bits after the binary point. In other words, the 1's bit of the answer
420: is almost always 1. THE FINAL BIT OF THE ANSWER IS 0 IFF n*2^i = THE
421: ANSWER RETURNED EXACTLY, WITH A 0 FINAL BIT.
422:
423:
424: To try again, more succintly: the answer is correct to within 1, and
425: the 1's bit of the answer will be 0 only if the answer is exactly
426: correct. */
427:
428: lispval
429: Lsbiglsh()
430: {
431: register struct argent *mylbot = lbot;
432: chkarg(2,"sticky-bignum-leftshift");
433: return(Ibiglsh(lbot->val,lbot[1].val,STICKY));
434: }
435: lispval
436: Lbiglsh()
437: {
438: register struct argent *mylbot = lbot;
439: chkarg(2,"bignum-leftshift");
440: return(Ibiglsh(lbot->val,lbot[1].val,TOEVEN));
441: }
442: lispval
443: HackHex() /* this is a one minute function so drb and kls can debug biglsh */
444: /* (HackHex i) returns a string which is the result of printing i in hex */
445: {
446: register struct argent *mylbot = lbot;
447: char buf[32];
448: sprintf(buf,"%lx",lbot->val->i);
449: return((lispval)inewstr(buf));
450: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.