/*
* 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,
0.5,
1.0,
68719476736.0,
536870912.0,
48.0,
16.0,
1.52587890625000000000e-05,
2.86102294921875000000e-06,
5.96046447753906250000e-08,
3.72529029846191406250e-09,
1.70530256582424044609e-13,
7.10542735760100185871e-15,
8.67361737988403547206e-19,
2.16840434497100886801e-19,
1.27054942088145050860e-21,
1.21169035041947413311e-27,
9.62964972193617926528e-35,
4.70197740328915003187e-38
};
#define zero C[0]
static const unsigned
#ifdef __sparcv9
/*
* _Qp_sqrt(pz, x) sets *pz = sqrt(*x).
*/
void
#else
/*
* _Q_sqrt(x) returns sqrt(*x).
*/
union longdouble
_Q_sqrt(const union longdouble *x)
#endif /* __sparcv9 */
{
union longdouble z;
union xdouble u;
if (QUAD_ISZERO(*x)) {
Z = *x;
QUAD_RETURN(Z);
}
/* handle nan and inf cases */
x->l.frac4) {
if (!(x->l.msw & 0x8000)) {
/* snan, signal invalid */
__quad_fsqrtq(x, &Z);
} else {
Z = *x;
Z.l.msw |= 0x8000;
}
QUAD_RETURN(Z);
}
Z = *x;
QUAD_RETURN(Z);
}
if (x->l.msw & 0x80000000) {
/* sqrt(-inf), signal invalid */
__quad_fsqrtq(x, &Z);
} else {
Z.l.msw = 0x7fffffff;
}
QUAD_RETURN(Z);
}
/* sqrt(inf), return inf */
Z = *x;
QUAD_RETURN(Z);
}
/* handle negative numbers */
if (xm & 0x80000000) {
__quad_fsqrtq(x, &Z);
} else {
Z.l.msw = 0x7fffffff;
}
QUAD_RETURN(Z);
}
/* now x is finite, positive */
__quad_setfsrp((unsigned *)&fsr_re);
/* get the normalized significand and exponent */
if (ex) {
lx |= 0x10000;
} else {
ex = 1;
wx[2] = 0;
ex = -31;
ex = -63;
} else {
ex = -95;
}
while ((lx & 0x10000) == 0) {
ex--;
}
}
if (ez & 1) {
/* make exponent even */
ez--;
}
/* extract the significands into doubles */
c = twom16;
c *= twom24;
c *= twom24;
0xffffff)) * c;
c *= twom24;
0xffffff)) * c;
c *= twom24;
/* approximate the divisor for the Newton iteration */
c = __quad_dp_sqrt(&c);
/* compute the first five "digits" of the square root */
r[0] += c;
r[0] += c;
r[0] += c;
/* 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;
/* adjust exponent and strip off integer bit */
/* 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 */
/* round and raise exceptions */
if (c != zero) {
/* decide whether to round the fraction up */
/* round up and renormalize if necessary */
if (++frac4 == 0)
if (++frac3 == 0)
if (++frac2 == 0)
if (++msw == 0x10000) {
msw = 0;
ez++;
}
}
}
/* stow the result */
__quad_fsqrtq(x, &Z);
} else {
Z = z;
}
QUAD_RETURN(Z);
}