198 lines
4.7 KiB
C
198 lines
4.7 KiB
C
#ifdef sccsid
|
|
static char sccsid[] = "@(#)_Qfaddsub.c 1.1 94/10/31 SMI";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include "_Qquad.h"
|
|
#include "_Qglobals.h"
|
|
|
|
PRIVATE void
|
|
true_add(px, py, pz)
|
|
unpacked *px, *py, *pz;
|
|
|
|
{
|
|
unsigned c;
|
|
unpacked *pt;
|
|
|
|
if ((int) px->fpclass < (int) py->fpclass) { /* Reverse. */
|
|
pt = py;
|
|
py = px;
|
|
px = pt;
|
|
}
|
|
/* Now class(x) >= class(y). */
|
|
switch (px->fpclass) {
|
|
case fp_quiet: /* NaN + x -> NaN */
|
|
case fp_signaling: /* NaN + x -> NaN */
|
|
case fp_infinity: /* Inf + x -> Inf */
|
|
case fp_zero: /* 0 + 0 -> 0 */
|
|
*pz = *px;
|
|
return;
|
|
default:
|
|
if (py->fpclass == fp_zero) {
|
|
*pz = *px;
|
|
return;
|
|
}
|
|
}
|
|
/* Now z is normal or subnormal. */
|
|
/* Now y is normal or subnormal. */
|
|
if (px->exponent < py->exponent) { /* Reverse. */
|
|
pt = py;
|
|
py = px;
|
|
px = pt;
|
|
}
|
|
/* Now class(x) >= class(y). */
|
|
pz->fpclass = px->fpclass;
|
|
pz->sign = px->sign;
|
|
pz->exponent = px->exponent;
|
|
pz->rounded = pz->sticky = 0;
|
|
|
|
if (px->exponent != py->exponent) { /* pre-alignment required */
|
|
fpu_rightshift(py, pz->exponent - py->exponent);
|
|
pz->rounded = py->rounded;
|
|
pz->sticky = py->sticky;
|
|
}
|
|
c = 0;
|
|
c = fpu_add3wc(&(pz->significand[3]),px->significand[3],
|
|
py->significand[3],c);
|
|
c = fpu_add3wc(&(pz->significand[2]),px->significand[2],
|
|
py->significand[2],c);
|
|
c = fpu_add3wc(&(pz->significand[1]),px->significand[1],
|
|
py->significand[1],c);
|
|
c = fpu_add3wc(&(pz->significand[0]),px->significand[0],
|
|
py->significand[0],c);
|
|
|
|
/* Handle carry out of msb. */
|
|
if(pz->significand[0]>=0x20000) {
|
|
fpu_rightshift(pz, 1); /* Carried out bit. */
|
|
pz->exponent ++; /* Renormalize. */
|
|
}
|
|
return;
|
|
}
|
|
|
|
PRIVATE void
|
|
true_sub(px, py, pz)
|
|
unpacked *px, *py, *pz;
|
|
|
|
{
|
|
unsigned *z,g,s,r,c;
|
|
int n;
|
|
unpacked *pt;
|
|
|
|
if ((int) px->fpclass < (int) py->fpclass) { /* Reverse. */
|
|
pt = py;
|
|
py = px;
|
|
px = pt;
|
|
}
|
|
/* Now class(x) >= class(y). */
|
|
*pz = *px; /* Tentative difference: x. */
|
|
switch (pz->fpclass) {
|
|
case fp_quiet: /* NaN - x -> NaN */
|
|
case fp_signaling: /* NaN - x -> NaN */
|
|
return;
|
|
case fp_infinity: /* Inf - x -> Inf */
|
|
if (py->fpclass == fp_infinity) {
|
|
fpu_error_nan(pz); /* Inf - Inf -> NaN */
|
|
pz->fpclass = fp_quiet;
|
|
}
|
|
return;
|
|
case fp_zero: /* 0 - 0 -> 0 */
|
|
pz->sign = (fp_direction == fp_negative);
|
|
return;
|
|
default:
|
|
if (py->fpclass == fp_zero)
|
|
return;
|
|
}
|
|
|
|
/* x and y are both normal or subnormal. */
|
|
|
|
if (px->exponent < py->exponent) { /* Reverse. */
|
|
pt = py;
|
|
py = px;
|
|
px = pt;
|
|
}
|
|
/* Now exp(x) >= exp(y). */
|
|
pz->fpclass = px->fpclass;
|
|
pz->sign = px->sign;
|
|
pz->exponent = px->exponent;
|
|
pz->rounded = 0;
|
|
pz->sticky = 0;
|
|
z = pz->significand;
|
|
|
|
if (px->exponent == py->exponent) { /* no pre-alignment required */
|
|
c = 0;
|
|
c = fpu_sub3wc(&z[3],px->significand[3],py->significand[3],c);
|
|
c = fpu_sub3wc(&z[2],px->significand[2],py->significand[2],c);
|
|
c = fpu_sub3wc(&z[1],px->significand[1],py->significand[1],c);
|
|
c = fpu_sub3wc(&z[0],px->significand[0],py->significand[0],c);
|
|
if((z[0]|z[1]|z[2]|z[3])==0) { /* exact zero result */
|
|
pz->sign = (fp_direction == fp_negative);
|
|
pz->fpclass = fp_zero;
|
|
return;
|
|
}
|
|
if(z[0]>=0x20000) { /* sign reversal occurred */
|
|
pz->sign = py->sign;
|
|
c = 0;
|
|
c = fpu_neg2wc(&z[3],z[3],c);
|
|
c = fpu_neg2wc(&z[2],z[2],c);
|
|
c = fpu_neg2wc(&z[1],z[1],c);
|
|
c = fpu_neg2wc(&z[0],z[0],c);
|
|
}
|
|
fpu_normalize(pz);
|
|
return;
|
|
} else { /* pre-alignment required */
|
|
fpu_rightshift(py, pz->exponent - py->exponent - 1);
|
|
r = py->rounded; /* rounded bit */
|
|
s = py->sticky; /* sticky bit */
|
|
fpu_rightshift(py, 1);
|
|
g = py->rounded; /* guard bit */
|
|
if(s!=0) r = (r==0);
|
|
if((r|s)!=0) g = (g==0);/* guard and rounded bits of z */
|
|
c = ((g|r|s)!=0);
|
|
c = fpu_sub3wc(&z[3],px->significand[3],py->significand[3],c);
|
|
c = fpu_sub3wc(&z[2],px->significand[2],py->significand[2],c);
|
|
c = fpu_sub3wc(&z[1],px->significand[1],py->significand[1],c);
|
|
c = fpu_sub3wc(&z[0],px->significand[0],py->significand[0],c);
|
|
|
|
if(z[0]>=0x10000) { /* don't need post-shifted */
|
|
pz->sticky = s|r;
|
|
pz->rounded = g;
|
|
} else { /* post-shifted left 1 bit */
|
|
pz->sticky = s;
|
|
pz->rounded = r;
|
|
pz->significand[0] = (z[0]<<1)|((z[1]&0x80000000)>>31);
|
|
pz->significand[1] = (z[1]<<1)|((z[2]&0x80000000)>>31);
|
|
pz->significand[2] = (z[2]<<1)|((z[3]&0x80000000)>>31);
|
|
pz->significand[3] = (z[3]<<1)|g;
|
|
pz->exponent -= 1;
|
|
if(z[0]<0x10000) fpu_normalize(pz);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
_fp_add(px, py, pz)
|
|
unpacked *px, *py, *pz;
|
|
|
|
{
|
|
if (px->sign == py->sign)
|
|
true_add(px, py, pz);
|
|
else
|
|
true_sub(px, py, pz);
|
|
}
|
|
|
|
void
|
|
_fp_sub(px, py, pz)
|
|
unpacked *px, *py, *pz;
|
|
|
|
{
|
|
py->sign = 1 - py->sign;
|
|
if (px->sign == py->sign)
|
|
true_add(px, py, pz);
|
|
else
|
|
true_sub(px, py, pz);
|
|
}
|