/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "quad.h"
static const double C[] = {
0.0,
1.0,
68719476736.0,
402653184.0,
24.0,
16.0,
3.66210937500000000000e-04,
1.52587890625000000000e-05,
1.43051147460937500000e-06,
5.96046447753906250000e-08,
3.72529029846191406250e-09,
2.18278728425502777100e-11,
8.52651282912120223045e-14,
3.55271367880050092936e-15,
1.30104260698260532081e-18,
8.67361737988403547206e-19,
2.16840434497100886801e-19,
3.17637355220362627151e-22,
7.75481824268463445192e-26,
4.62223186652936604733e-33,
9.62964972193617926528e-35,
4.70197740328915003187e-38,
2.75506488473973634680e-40,
};
#define zero C[0]
static const unsigned int
#ifdef __sparcv9
/*
* _Qp_div(pz, x, y) sets *pz = *x / *y.
*/
void
const union longdouble *y)
#else
/*
* _Q_div(x, y) returns *x / *y.
*/
union longdouble
#endif /* __sparcv9 */
{
union longdouble z;
union xdouble u;
/* handle nan and inf cases */
/* handle nan cases according to V9 app. B */
if (QUAD_ISNAN(*y)) {
if (!(y->l.msw & 0x8000)) {
/* snan, signal invalid */
__quad_fdivq(x, y, &Z);
} else {
Z = *y;
Z.l.msw |= 0x8000;
}
QUAD_RETURN(Z);
/* snan, signal invalid */
__quad_fdivq(x, y, &Z);
} else {
Z = *x;
Z.l.msw |= 0x8000;
}
QUAD_RETURN(Z);
}
Z = *y;
QUAD_RETURN(Z);
}
if (QUAD_ISNAN(*x)) {
if (!(x->l.msw & 0x8000)) {
/* snan, signal invalid */
__quad_fdivq(x, y, &Z);
} else {
Z = *x;
Z.l.msw |= 0x8000;
}
QUAD_RETURN(Z);
}
Z = *x;
QUAD_RETURN(Z);
}
if (xm == 0x7fff0000) {
/* x is inf */
if (ym == 0x7fff0000) {
/* inf / inf, signal invalid */
__quad_fdivq(x, y, &Z);
} else {
Z.l.msw = 0x7fffffff;
Z.l.frac4 = 0xffffffff;
}
QUAD_RETURN(Z);
}
/* inf / finite, return inf */
QUAD_RETURN(Z);
}
/* y is inf */
QUAD_RETURN(Z);
}
/* handle zero cases */
if (QUAD_ISZERO(*x)) {
if (QUAD_ISZERO(*y)) {
/* zero / zero, signal invalid */
__quad_fdivq(x, y, &Z);
} else {
Z.l.msw = 0x7fffffff;
Z.l.frac4 = 0xffffffff;
}
QUAD_RETURN(Z);
}
/* zero / nonzero, return zero */
QUAD_RETURN(Z);
}
if (QUAD_ISZERO(*y)) {
/* nonzero / zero, signal zero divide */
__quad_fdivq(x, y, &Z);
} else {
}
QUAD_RETURN(Z);
}
}
/* now x and y are finite, nonzero */
/* get their normalized significands and exponents */
if (ex) {
lx |= 0x10000;
} else {
ex = 1;
wx[2] = 0;
ex = -31;
ex = -63;
} else {
ex = -95;
}
while ((lx & 0x10000) == 0) {
ex--;
}
}
if (ey) {
ly |= 0x10000;
} else {
ey = 1;
wy[2] = 0;
ey = -31;
ey = -63;
} else {
ey = -95;
}
while ((ly & 0x10000) == 0) {
ey--;
}
}
/* extract the significands into doubles */
c = twom16;
c *= twom24;
c *= twom24;
c *= twom24;
c *= twom24;
/* approximate the reciprocal of y */
/* compute the first five "digits" of the quotient */
xx[0] -= c;
xx[1] -= c;
xx[2] -= c;
xx[3] = c - d;
xx[0] -= c;
xx[1] -= c;
xx[2] -= c;
xx[3] = c - d;
xx[0] -= c;
xx[1] -= c;
c = (d + three2m109) - three2m109;
xx[2] -= c;
xx[3] = c - d;
xx[0] -= c;
c = (d + three2m109) - three2m109;
xx[1] -= c;
c = (d + three2m133) - three2m133;
xx[2] -= c;
xx[3] = c - d;
/* reduce to three doubles, making sure zz[1] is positive */
/* if the third term might lie on a rounding boundary, perturb it */
/* here we just need to get the sign of the remainder */
if (c < zero)
else if (c > zero)
}
/*
* to make all terms nonnegative (note that we can't encounter a
* borrow so large that the roundoff is unrepresentable because
* we took care to make zz[1] positive above)
*/
zz[1] = c;
zz[0] = c;
/* check for borrow */
if (c < one) {
/* postnormalize */
ez--;
}
/* if exponent > 0 strip off integer bit, else denormalize */
if (ez > 0) {
ibit = 1;
} else {
ibit = 0;
if (ez > -128)
else
u.l.hi = 0x37e00000;
u.l.lo = 0;
zz[0] *= u.d;
zz[1] *= u.d;
zz[2] *= u.d;
ez = 0;
}
/* the first 48 bits of fraction come from zz[0] */
/* the next 32 come from zz[0] and zz[1] */
/* condense the remaining fraction; errors here won't matter */
zz[0] = c;
/* get the last word of fraction */
/* keep track of what's left for rounding; note that the error */
/* in computing c will be non-negative due to rounding mode */
/* get the rounding mode, fudging directed rounding modes */
/* as though the result were positive */
if (sign)
/* round and raise exceptions */
if (c != zero) {
/* decide whether to round the fraction up */
zz[1])))))) {
/* round up and renormalize if necessary */
if (++frac4 == 0)
if (++frac3 == 0)
if (++frac2 == 0)
if (++msw == 0x10000) {
msw = 0;
ez++;
}
}
}
if (ez >= 0x7fff) {
} else {
}
} else {
/* !ibit => exact result was tiny before rounding, */
/* t nonzero => result delivered is inexact */
if (!ibit) {
if (c != zero)
}
}
__quad_fdivq(x, y, &Z);
} else {
Z = z;
}
QUAD_RETURN(Z);
}