Blob


1 #include "os.h"
2 #include <mp.h>
3 #include "dat.h"
5 // division ala knuth, seminumerical algorithms, pp 237-238
6 // the numbers are stored backwards to what knuth expects so j
7 // counts down rather than up.
9 void
10 mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder)
11 {
12 int j, s, vn, sign;
13 mpdigit qd, *up, *vp, *qp;
14 mpint *u, *v, *t;
16 // divide bv zero
17 if(divisor->top == 0)
18 abort();
20 // quick check
21 if(mpmagcmp(dividend, divisor) < 0){
22 if(remainder != nil)
23 mpassign(dividend, remainder);
24 if(quotient != nil)
25 mpassign(mpzero, quotient);
26 return;
27 }
29 // D1: shift until divisor, v, has hi bit set (needed to make trial
30 // divisor accurate)
31 qd = divisor->p[divisor->top-1];
32 for(s = 0; (qd & mpdighi) == 0; s++)
33 qd <<= 1;
34 u = mpnew((dividend->top+2)*Dbits + s);
35 if(s == 0 && divisor != quotient && divisor != remainder) {
36 mpassign(dividend, u);
37 v = divisor;
38 } else {
39 mpleft(dividend, s, u);
40 v = mpnew(divisor->top*Dbits);
41 mpleft(divisor, s, v);
42 }
43 up = u->p+u->top-1;
44 vp = v->p+v->top-1;
45 vn = v->top;
47 // D1a: make sure high digit of dividend is less than high digit of divisor
48 if(*up >= *vp){
49 *++up = 0;
50 u->top++;
51 }
53 // storage for multiplies
54 t = mpnew(4*Dbits);
56 qp = nil;
57 if(quotient != nil){
58 mpbits(quotient, (u->top - v->top)*Dbits);
59 quotient->top = u->top - v->top;
60 qp = quotient->p+quotient->top-1;
61 }
63 // D2, D7: loop on length of dividend
64 for(j = u->top; j > vn; j--){
66 // D3: calculate trial divisor
67 mpdigdiv(up-1, *vp, &qd);
69 // D3a: rule out trial divisors 2 greater than real divisor
70 if(vn > 1) for(;;){
71 memset(t->p, 0, 3*Dbytes); // mpvecdigmuladd adds to what's there
72 mpvecdigmuladd(vp-1, 2, qd, t->p);
73 if(mpveccmp(t->p, 3, up-2, 3) > 0)
74 qd--;
75 else
76 break;
77 }
79 // D4: u -= v*qd << j*Dbits
80 sign = mpvecdigmulsub(v->p, vn, qd, up-vn);
81 if(sign < 0){
83 // D6: trial divisor was too high, add back borrowed
84 // value and decrease divisor
85 mpvecadd(up-vn, vn+1, v->p, vn, up-vn);
86 qd--;
87 }
89 // D5: save quotient digit
90 if(qp != nil)
91 *qp-- = qd;
93 // push top of u down one
94 u->top--;
95 *up-- = 0;
96 }
97 if(qp != nil){
98 mpnorm(quotient);
99 if(dividend->sign != divisor->sign)
100 quotient->sign = -1;
103 if(remainder != nil){
104 mpright(u, s, remainder); // u is the remainder shifted
105 remainder->sign = dividend->sign;
108 mpfree(t);
109 mpfree(u);
110 if(v != divisor)
111 mpfree(v);