xref: /illumos-gate/usr/src/lib/libmp/common/mdiv.c (revision 942c5e3c2dd127463517e5cc1694ee94ca45e021)
1 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
2 /*	  All Rights Reserved  	*/
3 
4 
5 /*
6  * Copyright (c) 1980 Regents of the University of California.
7  * All rights reserved.  The Berkeley software License Agreement
8  * specifies the terms and conditions for redistribution.
9  */
10 /* 	Portions Copyright(c) 1988, Sun Microsystems Inc.	*/
11 /*	All Rights Reserved					*/
12 
13 /*
14  * Copyright (c) 1997, by Sun Microsystems, Inc.
15  * All rights reserved.
16  */
17 
18 #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.1	*/
19 
20 /* LINTLIBRARY */
21 
22 #include <mp.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include "libmp.h"
27 
28 static void m_div(MINT *, MINT *, MINT *, MINT *);
29 
30 void
31 mp_mdiv(MINT *a, MINT *b, MINT *q, MINT *r)
32 {
33 	MINT x, y;
34 	int sign;
35 
36 	sign = 1;
37 	x.len = y.len = 0;
38 	_mp_move(a, &x);
39 	_mp_move(b, &y);
40 	if (x.len < 0) {
41 		sign = -1;
42 		x.len = -x.len;
43 	}
44 	if (y.len < 0) {
45 		sign = -sign;
46 		y.len = -y.len;
47 	}
48 	_mp_xfree(q);
49 	_mp_xfree(r);
50 	m_div(&x, &y, q, r);
51 	if (sign == -1) {
52 		q->len = -q->len;
53 		r->len = -r->len;
54 	}
55 	_mp_xfree(&x);
56 	_mp_xfree(&y);
57 }
58 
59 static int
60 m_dsb(int qx, int n, short *a, short *b)
61 {
62 	int borrow;
63 	int s3b2shit;
64 	int j;
65 	short fifteen = 15;
66 	short *aptr, *bptr;
67 #ifdef DEBUGDSB
68 	(void) printf("m_dsb %d %d %d %d\n", qx, n, *a, *b);
69 #endif
70 
71 	borrow = 0;
72 	aptr = a;
73 	bptr = b;
74 	for (j = n; j > 0; j--) {
75 #ifdef DEBUGDSB
76 		(void) printf("1 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
77 		    *bptr, *aptr);
78 #endif
79 		borrow -= (*aptr++) * qx - *bptr;
80 #ifdef DEBUGDSB
81 		(void) printf("2 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
82 		    *bptr, *aptr);
83 #endif
84 		*bptr++ = (short)(borrow & 077777);
85 #ifdef DEBUGDSB
86 		(void) printf("3 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
87 		    *bptr, *aptr);
88 #endif
89 		if (borrow >= 0) borrow >>= fifteen; /* 3b2 */
90 		else borrow = 0xfffe0000 | (borrow >> fifteen);
91 #ifdef DEBUGDSB
92 		(void) printf("4 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
93 		    *bptr, *aptr);
94 #endif
95 	}
96 	borrow += *bptr;
97 	*bptr = (short)(borrow & 077777);
98 		if (borrow >= 0) s3b2shit = borrow >> fifteen; /* 3b2 */
99 		else s3b2shit = 0xfffe0000 | (borrow >> fifteen);
100 	if (s3b2shit == 0) {
101 #ifdef DEBUGDSB
102 	(void) printf("mdsb 0\n");
103 #endif
104 		return (0);
105 	}
106 	borrow = 0;
107 	aptr = a;
108 	bptr = b;
109 	for (j = n; j > 0; j--) {
110 		borrow += *aptr++ + *bptr;
111 		*bptr++ = (short)(borrow & 077777);
112 		if (borrow >= 0) borrow >>= fifteen; /* 3b2 */
113 		else borrow = 0xfffe0000 | (borrow >>fifteen);
114 	}
115 #ifdef DEBUGDSB
116 	(void) printf("mdsb 1\n");
117 #endif
118 	return (1);
119 }
120 
121 static int
122 m_trq(short v1, short v2, short u1, short u2, short u3)
123 {
124 	short d;
125 	int x1;
126 	int c1;
127 
128 	c1 = u1 * 0100000 + u2;
129 	if (u1 == v1) {
130 		d = 077777;
131 	} else {
132 		d = (short)(c1 / v1);
133 	}
134 	do {
135 		x1 = c1 - v1 * d;
136 		x1 = x1 * 0100000 + u3 - v2 * d;
137 		--d;
138 	} while (x1 < 0);
139 #ifdef DEBUGMTRQ
140 	(void) printf("mtrq %d %d %d %d %d %d\n", v1, v2, u1, u2, u3, (d+1));
141 #endif
142 	return ((int)d + 1);
143 }
144 
145 static void
146 m_div(MINT *a, MINT *b, MINT *q, MINT *r)
147 {
148 	MINT u, v, x, w;
149 	short d;
150 	short *qval;
151 	short *uval;
152 	int j;
153 	int qq;
154 	int n;
155 	short v1;
156 	short v2;
157 
158 	u.len = v.len = x.len = w.len = 0;
159 	if (b->len == 0) {
160 		_mp_fatal("mdiv divide by zero");
161 		return;
162 	}
163 	if (b->len == 1) {
164 		r->val = _mp_xalloc(1, "m_div1");
165 		mp_sdiv(a, b->val[0], q, r->val);
166 		if (r->val[0] == 0) {
167 			free(r->val);
168 			r->len = 0;
169 		} else {
170 			r->len = 1;
171 		}
172 		return;
173 	}
174 	if (a -> len < b -> len) {
175 		q->len = 0;
176 		r->len = a->len;
177 		r->val = _mp_xalloc(r->len, "m_div2");
178 		for (qq = 0; qq < r->len; qq++) {
179 			r->val[qq] = a->val[qq];
180 		}
181 		return;
182 	}
183 	x.len = 1;
184 	x.val = &d;
185 	n = b->len;
186 	d = 0100000 / (b->val[n - 1] + 1);
187 	mp_mult(a, &x, &u); /* subtle: relies on mult allocing extra space */
188 	mp_mult(b, &x, &v);
189 #ifdef DEBUG_MDIV
190 	(void) printf("  u=%s\n", mtox(&u));
191 	(void) printf("  v=%s\n", mtox(&v));
192 #endif
193 	v1 = v.val[n - 1];
194 	v2 = v.val[n - 2];
195 	qval = _mp_xalloc(a -> len - n + 1, "m_div3");
196 	uval = u.val;
197 	for (j = a->len - n; j >= 0; j--) {
198 		qq = m_trq(v1, v2, uval[j + n], uval[j + n - 1],
199 							uval[j + n - 2]);
200 		if (m_dsb(qq, n, v.val, uval + j))
201 			qq -= 1;
202 		qval[j] = (short)qq;
203 	}
204 	x.len = n;
205 	x.val = u.val;
206 	_mp_mcan(&x);
207 #ifdef DEBUG_MDIV
208 	(void) printf("  x=%s\n", mtox(&x));
209 	(void) printf("  d(in)=%d\n", (d));
210 #endif
211 	mp_sdiv(&x, d, &w, &d);
212 #ifdef DEBUG_MDIV
213 	(void) printf("  w=%s\n", mtox(&w));
214 	(void) printf("  d(out)=%d\n", (d));
215 #endif
216 	r->len = w.len;
217 	r->val = w.val;
218 	q->val = qval;
219 	qq = a->len - n + 1;
220 	if (qq > 0 && qval[qq - 1] == 0)
221 		qq -= 1;
222 	q->len = qq;
223 	if (qq == 0)
224 		free(qval);
225 	if (x.len != 0)
226 		_mp_xfree(&u);
227 	_mp_xfree(&v);
228 }
229