. service tells you which device it couldn't stat
[minix3.git] / lib / float / div_ext.c
blobbb9531178f4b046e6d5a9bab6ffed6247879d1f1
1 /*
2 (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 See the copyright notice in the ACK home directory, in the file "Copyright".
4 */
6 /* $Header$ */
8 /*
9 DIVIDE EXTENDED FORMAT
12 #include "FP_bias.h"
13 #include "FP_trap.h"
14 #include "FP_types.h"
17 November 15, 1984
19 This is a routine to do the work.
20 There are two versions:
21 One is based on the partial products method
22 and makes no use possible machine instructions
23 to divide (hardware dividers).
24 The other is used when USE_DIVIDE is defined. It is much faster on
25 machines with fast 4 byte operations.
27 /********************************************************/
29 void
30 div_ext(e1,e2)
31 EXTEND *e1,*e2;
33 short error = 0;
34 B64 result;
35 register unsigned long *lp;
36 #ifndef USE_DIVIDE
37 short count;
38 #else
39 unsigned short u[9], v[5];
40 register int j;
41 register unsigned short *u_p = u;
42 int maxv = 4;
43 #endif
45 if ((e2->m1 | e2->m2) == 0) {
47 * Exception 8.2 - Divide by zero
49 trap(EFDIVZ);
50 e1->m1 = e1->m2 = 0L;
51 e1->exp = EXT_MAX;
52 return;
54 if ((e1->m1 | e1->m2) == 0) { /* 0 / anything == 0 */
55 e1->exp = 0; /* make sure */
56 return;
58 #ifndef USE_DIVIDE
60 * numbers are right shifted one bit to make sure
61 * that m1 is quaranteed to be larger if its
62 * maximum bit is set
64 b64_rsft(&e1->mantissa); /* 64 bit shift right */
65 b64_rsft(&e2->mantissa); /* 64 bit shift right */
66 e1->exp++;
67 e2->exp++;
68 #endif
69 /* check for underflow, divide by zero, etc */
70 e1->sign ^= e2->sign;
71 e1->exp -= e2->exp;
73 #ifndef USE_DIVIDE
74 /* do division of mantissas */
75 /* uses partial product method */
76 /* init control variables */
78 count = 64;
79 result.h_32 = 0L;
80 result.l_32 = 0L;
82 /* partial product division loop */
84 while (count--) {
85 /* first left shift result 1 bit */
86 /* this is ALWAYS done */
88 b64_lsft(&result);
90 /* compare dividend and divisor */
91 /* if dividend >= divisor add a bit */
92 /* and subtract divisior from dividend */
94 if ( (e1->m1 < e2->m1) ||
95 ((e1->m1 == e2->m1) && (e1->m2 < e2->m2) ))
96 ; /* null statement */
97 /* i.e., don't add or subtract */
98 else {
99 result.l_32++; /* ADD */
100 if (e2->m2 > e1->m2)
101 e1->m1 -= 1; /* carry in */
102 e1->m1 -= e2->m1; /* do SUBTRACTION */
103 e1->m2 -= e2->m2; /* SUBTRACTION */
106 /* shift dividend left one bit OR */
107 /* IF it equals ZERO we can break out */
108 /* of the loop, but still must shift */
109 /* the quotient the remaining count bits */
110 /* NB save the results of this test in error */
111 /* if not zero, then the result is inexact. */
112 /* this would be reported in IEEE standard */
114 /* lp points to dividend */
115 lp = &e1->m1;
117 error = ((*lp | *(lp+1)) != 0L) ? 1 : 0;
118 if (error) { /* more work */
119 /* assume max bit == 0 (see above) */
120 b64_lsft(&e1->mantissa);
121 continue;
123 else
124 break; /* leave loop */
125 } /* end of divide by subtraction loop */
127 if (count > 0) {
128 lp = &result.h_32;
129 if (count > 31) { /* move to higher word */
130 *lp = *(lp+1);
131 count -= 32;
132 *(lp+1) = 0L; /* clear low word */
134 if (*lp)
135 *lp <<= count; /* shift rest of way */
136 lp++; /* == &result.l_32 */
137 if (*lp) {
138 result.h_32 |= (*lp >> 32-count);
139 *lp <<= count;
142 #else /* USE_DIVIDE */
144 u[4] = (e1->m2 & 1) << 15;
145 b64_rsft(&(e1->mantissa));
146 u[0] = e1->m1 >> 16;
147 u[1] = e1->m1;
148 u[2] = e1->m2 >> 16;
149 u[3] = e1->m2;
150 u[5] = 0; u[6] = 0; u[7] = 0;
151 v[1] = e2->m1 >> 16;
152 v[2] = e2->m1;
153 v[3] = e2->m2 >> 16;
154 v[4] = e2->m2;
155 while (! v[maxv]) maxv--;
156 result.h_32 = 0;
157 result.l_32 = 0;
158 lp = &result.h_32;
161 * Use an algorithm of Knuth (The art of programming, Seminumerical
162 * algorithms), to divide u by v. u and v are both seen as numbers
163 * with base 65536.
165 for (j = 0; j <= 3; j++, u_p++) {
166 unsigned long q_est, temp;
168 if (j == 2) lp++;
169 if (u_p[0] == 0 && u_p[1] < v[1]) continue;
170 temp = ((unsigned long)u_p[0] << 16) + u_p[1];
171 if (u_p[0] >= v[1]) {
172 q_est = 0x0000FFFFL;
174 else {
175 q_est = temp / v[1];
177 temp -= q_est * v[1];
178 while (temp < 0x10000 && v[2]*q_est > ((temp<<16)+u_p[2])) {
179 q_est--;
180 temp += v[1];
182 /* Now, according to Knuth, we have an estimate of the
183 quotient, that is either correct or one too big, but
184 almost always correct.
186 if (q_est != 0) {
187 int i;
188 unsigned long k = 0;
189 int borrow = 0;
191 for (i = maxv; i > 0; i--) {
192 unsigned long tmp = q_est * v[i] + k + borrow;
193 unsigned short md = tmp;
195 borrow = (md > u_p[i]);
196 u_p[i] -= md;
197 k = tmp >> 16;
199 k += borrow;
200 borrow = u_p[0] < k;
201 u_p[0] -= k;
203 if (borrow) {
204 /* So, this does not happen often; the estimate
205 was one too big; correct this
207 *lp |= (j & 1) ? (q_est - 1) : ((q_est-1)<<16);
208 borrow = 0;
209 for (i = maxv; i > 0; i--) {
210 unsigned long tmp
211 = v[i]+(unsigned long)u_p[i]+borrow;
213 u_p[i] = tmp;
214 borrow = tmp >> 16;
216 u_p[0] += borrow;
218 else *lp |= (j & 1) ? q_est : (q_est<<16);
221 #ifdef EXCEPTION_INEXACT
222 u_p = &u[0];
223 for (j = 7; j >= 0; j--) {
224 if (*u_p++) {
225 error = 1;
226 break;
229 #endif
230 #endif
232 #ifdef EXCEPTION_INEXACT
233 if (error) {
235 * report here exception 8.5 - Inexact
236 * from Draft 8.0 of IEEE P754:
237 * In the absence of an invalid operation exception,
238 * if the rounded result of an operation is not exact or if
239 * it overflows without a trap, then the inexact exception
240 * shall be assigned. The rounded or overflowed result
241 * shall be delivered to the destination.
243 INEXACT();
244 #endif
245 e1->mantissa = result;
247 nrm_ext(e1);
248 if (e1->exp < EXT_MIN) {
250 * Exception 8.4 - Underflow
252 trap(EFUNFL); /* underflow */
253 e1->exp = EXT_MIN;
254 e1->m1 = e1->m2 = 0L;
255 return;
257 if (e1->exp >= EXT_MAX) {
259 * Exception 8.3 - Overflow
261 trap(EFOVFL); /* overflow */
262 e1->exp = EXT_MAX;
263 e1->m1 = e1->m2 = 0L;
264 return;