Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / usr.bin / lisp / franz / divbig.c
CommitLineData
bc51592a
C
1#ifndef lint
2static 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
19divbig(dividend, divisor, quotient, remainder)
20lispval 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));
80d1:
81 d = b /(*vbot +1);
82 dsmult(utop-1,ubot,d);
83 dsmult(ubot-1,vbot,d);
84
85d2: 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 }
96d8: 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!
111calqhat(ujp,v1p)
112register int *ujp, *v1p;
113{
114asm(" cmpl (r10),(r11) # v[1] == u[j] ??");
115asm(" beql 2f ");
116asm(" # calculate qhat and rhat simultaneously,");
117asm(" # qhat in r0");
118asm(" # rhat in r1");
119asm(" emul (r11),$0x40000000,4(r11),r4 # u[j]b+u[j+1] into r4,r5");
120asm(" ediv (r10),r4,r0,r1 # qhat = ((u[j]b+u[j+1])/v[1]) into r0");
121asm(" # (u[j]b+u[j+1] -qhat*v[1]) into r1");
122asm(" # called rhat");
123asm("1:");
124asm(" # check if v[2]*qhat > rhat*b+u[j+2]");
125asm(" emul r0,4(r10),$0,r2 # qhat*v[2] into r3,r2");
126asm(" emul r1,$0x40000000,8(r11),r8 #rhat*b + u[j+2] into r9,r8");
127asm(" # give up if r3,r2 <= r9,r8, otherwise iterate");
128asm(" subl2 r8,r2 # perform r3,r2 - r9,r8");
129asm(" sbwc r9,r3");
130asm(" bleq 3f # give up if negative or equal");
131asm(" decl r0 # otherwise, qhat = qhat - 1");
132asm(" addl2 (r10),r1 # since dec'ed qhat, inc rhat by v[1]");
133asm(" jbr 1b");
134asm("2: ");
135asm(" # get here if v[1]==u[j]");
136asm(" # set qhat to b-1");
137asm(" # rhat is easily calculated since if we substitute b-1 for qhat in");
138asm(" # the formula, then it simplifies to (u[j+1] + v[1])");
139asm(" # ");
140asm(" addl3 4(r11),(r10),r1 # rhat = u[j+1] + v[1]");
141asm(" movl $0x3fffffff,r0 # qhat = b-1");
142asm(" jbr 1b");
143asm("3:");
144}
145mlsb(utop,ubot,vtop,nqhat)
146register int *utop, *ubot, *vtop;
147register int nqhat;
148{
149asm(" clrl r0");
150asm("loop2: addl2 (r11),r0");
151asm(" emul r8,-(r9),r0,r2");
152asm(" extzv $0,$30,r2,(r11)");
153asm(" extv $30,$32,r2,r0");
154asm(" acbl r10,$-4,r11,loop2");
155}
156adback(utop,ubot,vtop)
157register int *utop, *ubot, *vtop;
158{
159asm(" clrl r0");
160asm("loop3: addl2 -(r9),r0");
161asm(" addl2 (r11),r0");
162asm(" extzv $0,$30,r0,(r11)");
163asm(" extv $30,$2,r0,r0");
164asm(" acbl r10,$-4,r11,loop3");
165}
166dsdiv(top,bot,div)
167register int* bot;
168{
169asm(" clrl r0");
170asm("loop4: emul r0,$0x40000000,(r11),r1");
171asm(" ediv 12(ap),r1,(r11),r0");
172asm(" acbl 4(ap),$4,r11,loop4");
173}
174dsmult(top,bot,mult)
175register int* top;
176{
177asm(" clrl r0");
178asm("loop5: emul 12(ap),(r11),r0,r1");
179asm(" extzv $0,$30,r1,(r11)");
180asm(" extv $30,$32,r1,r0");
181asm(" acbl 8(ap),$-4,r11,loop5");
182asm(" movl r1,4(r11)");
183}
184*/
185lispval
186export(top,bot)
187register 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
217Ihau(fix)
218register 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}
229lispval
230Lhau()
231{
232 register count;
233 register lispval handy;
234 register dum1,dum2;
235 lispval Labsval();
236
237 handy = lbot->val;
238top:
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}
256lispval
257Lhaipar()
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 */
268on1:
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 }
320done:
321 return(export(top + 1,bot));
322}
323#define STICKY 1
324#define TOEVEN 2
325lispval
326Ibiglsh(bignum,count,mode)
327lispval 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 */
350on1:
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
414To: sklower
415
416The idea is that the answer/2
417is equal to the exact answer/2 rounded towards - infinity. The final bit
418of the answer is the "or" of the true final bit, together with all true
419bits after the binary point. In other words, the 1's bit of the answer
420is almost always 1. THE FINAL BIT OF THE ANSWER IS 0 IFF n*2^i = THE
421ANSWER RETURNED EXACTLY, WITH A 0 FINAL BIT.
422
423
424To try again, more succintly: the answer is correct to within 1, and
425the 1's bit of the answer will be 0 only if the answer is exactly
426correct. */
427
428lispval
429Lsbiglsh()
430{
431 register struct argent *mylbot = lbot;
432 chkarg(2,"sticky-bignum-leftshift");
433 return(Ibiglsh(lbot->val,lbot[1].val,STICKY));
434}
435lispval
436Lbiglsh()
437{
438 register struct argent *mylbot = lbot;
439 chkarg(2,"bignum-leftshift");
440 return(Ibiglsh(lbot->val,lbot[1].val,TOEVEN));
441}
442lispval
443HackHex() /* 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}