127 lines
2.7 KiB
C
127 lines
2.7 KiB
C
/*
|
|
(c) copyright 1989 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
|
|
/* $Header$ */
|
|
|
|
#include "flt_misc.h"
|
|
|
|
flt_div(e1,e2,e3)
|
|
register flt_arith *e1,*e2,*e3;
|
|
{
|
|
long result[2];
|
|
register long *lp;
|
|
unsigned short u[9], v[5];
|
|
register int j;
|
|
register unsigned short *u_p = u;
|
|
int maxv = 4;
|
|
|
|
flt_status = 0;
|
|
e3->flt_sign = e1->flt_sign ^ e2->flt_sign;
|
|
if ((e2->m1 | e2->m2) == 0) {
|
|
flt_status = FLT_DIV0;
|
|
e3->flt_exp = EXT_MAX;
|
|
e3->m1 = 0x80000000;
|
|
e3->m2 = 0L;
|
|
return;
|
|
}
|
|
if ((e1->m1 | e1->m2) == 0) { /* 0 / anything == 0 */
|
|
e3->flt_exp = 0; /* make sure */
|
|
e3->m1 = e3->m2 = 0L;
|
|
e3->flt_sign = 0;
|
|
return;
|
|
}
|
|
e3->flt_exp = e1->flt_exp - e2->flt_exp;
|
|
|
|
u[4] = (e1->m2 & 1) << 15;
|
|
flt_b64_sft(&(e1->flt_mantissa),1);
|
|
flt_split(e1, u);
|
|
u[5] = 0; u[6] = 0; u[7] = 0;
|
|
flt_split(e2, &v[1]);
|
|
while (! v[maxv]) maxv--;
|
|
result[0] = 0;
|
|
result[1] = 0;
|
|
lp = result;
|
|
|
|
/*
|
|
* Use an algorithm of Knuth (The art of programming, Seminumerical
|
|
* algorithms), to divide u by v. u and v are both seen as numbers
|
|
* with base 65536.
|
|
*/
|
|
for (j = 0; j <= 3; j++, u_p++) {
|
|
long q_est, temp;
|
|
long v1 = v[1];
|
|
|
|
if (j == 2) lp++;
|
|
if (u_p[0] == 0 && u_p[1] < v[1]) continue;
|
|
temp = ((long)u_p[0] << 16) + u_p[1];
|
|
if (u_p[0] >= v[1]) {
|
|
q_est = 0x0000FFFFL;
|
|
}
|
|
else if (v[1] == 1) {
|
|
q_est = temp;
|
|
}
|
|
else if (temp >= 0) {
|
|
q_est = temp / v1;
|
|
}
|
|
else {
|
|
long rem;
|
|
q_est = (0x7FFFFFFF/v1)+((temp&0x7FFFFFFF)/v1);
|
|
rem = (0x7FFFFFFF%v1)+((temp&0x7FFFFFFF)%v1)+1;
|
|
while (rem >= v1) {
|
|
q_est++;
|
|
rem -= v1;
|
|
}
|
|
}
|
|
temp -= q_est * v1;
|
|
while (!(temp&0xFFFF0000) &&
|
|
ucmp((long)v[2]*q_est,(temp<<16)+(long)u_p[2]) > 0) {
|
|
q_est--;
|
|
temp += v1;
|
|
}
|
|
/* Now, according to Knuth, we have an estimate of the
|
|
quotient, that is either correct or one too big, but
|
|
almost always correct.
|
|
*/
|
|
if (q_est != 0) {
|
|
int i;
|
|
long k = 0;
|
|
int borrow = 0;
|
|
|
|
for (i = maxv; i > 0; i--) {
|
|
long tmp = q_est * (long)v[i] + k + borrow;
|
|
unsigned short md = tmp & 0xFFFF;
|
|
|
|
borrow = (md > u_p[i]);
|
|
u_p[i] -= md;
|
|
k = (tmp >> 16) & 0xFFFF;
|
|
}
|
|
k += borrow;
|
|
borrow = (long)u_p[0] < k;
|
|
u_p[0] -= k;
|
|
|
|
if (borrow) {
|
|
/* So, this does not happen often; the estimate
|
|
was one too big; correct this
|
|
*/
|
|
q_est--;
|
|
borrow = 0;
|
|
for (i = maxv; i > 0; i--) {
|
|
long tmp
|
|
= v[i]+(long)u_p[i]+borrow;
|
|
|
|
u_p[i] = tmp & 0xFFFF;
|
|
borrow = (tmp >> 16) & 0xFFFF;
|
|
}
|
|
u_p[0] += borrow;
|
|
}
|
|
*lp |= (j & 1) ? q_est : (q_est<<16);
|
|
}
|
|
}
|
|
e3->m1 = result[0];
|
|
e3->m2 = result[1];
|
|
|
|
flt_nrm(e3);
|
|
flt_chk(e3);
|
|
}
|