/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "libm.h"
#include "longdouble.h"
extern int __swapTE(int);
extern int __swapEX(int);
/*
* in struct longdouble, msw consists of
* unsigned short sgn:1;
* unsigned short exp:15;
* unsigned short frac1:16;
*/
#ifdef __LITTLE_ENDIAN
/* array indices used to access words within a double */
#define LOWORD 0
/* structure used to access words within a quad */
union longdouble {
struct {
unsigned int frac4;
unsigned int frac3;
unsigned int frac2;
unsigned int msw;
} l;
long double d;
};
/* default NaN returned for sqrt(neg) */
static const union longdouble
/* signalling NaN used to raise invalid */
static const union {
unsigned u[2];
double d;
#else
/* array indices used to access words within a double */
#define HIWORD 0
/* structure used to access words within a quad */
union longdouble {
struct {
unsigned int msw;
unsigned int frac2;
unsigned int frac3;
unsigned int frac4;
} l;
long double d;
};
/* default NaN returned for sqrt(neg) */
static const union longdouble
/* signalling NaN used to raise invalid */
static const union {
unsigned u[2];
double d;
#endif /* __LITTLE_ENDIAN */
static const double
/*
* Extract the exponent and normalized significand (represented as
* an array of five doubles) from a finite, nonzero quad.
*/
static int
{
union {
double d;
unsigned int l[2];
} u;
double b;
int ex;
/* get the normalized significand and exponent */
if (ex)
{
lx |= 0x10000;
w[0] = x->l.frac2;
w[1] = x->l.frac3;
w[2] = x->l.frac4;
}
else
{
{
w[0] = x->l.frac2;
w[1] = x->l.frac3;
w[2] = x->l.frac4;
ex = 1;
}
{
w[0] = x->l.frac3;
w[1] = x->l.frac4;
w[2] = 0;
ex = -31;
}
{
w[0] = x->l.frac4;
w[1] = w[2] = 0;
ex = -63;
}
else
{
w[0] = w[1] = w[2] = 0;
ex = -95;
}
while ((lx & 0x10000) == 0)
{
w[0] = (w[0] << 1) | (w[1] >> 31);
w[1] = (w[1] << 1) | (w[2] >> 31);
w[2] <<= 1;
ex--;
}
}
/* extract the significand into five doubles */
u.l[HIWORD] = 0x42300000;
u.l[LOWORD] = 0;
b = u.d;
s[0] = u.d - b;
u.l[HIWORD] = 0x40300000;
u.l[LOWORD] = 0;
b = u.d;
u.l[LOWORD] = w[0] & 0xffffff00;
s[1] = u.d - b;
u.l[HIWORD] = 0x3e300000;
u.l[LOWORD] = 0;
b = u.d;
u.l[HIWORD] |= w[0] & 0xff;
s[2] = u.d - b;
u.l[HIWORD] = 0x3c300000;
u.l[LOWORD] = 0;
b = u.d;
s[3] = u.d - b;
u.l[HIWORD] = 0x3c300000;
u.l[LOWORD] = 0;
b = u.d;
s[4] = u.d - b;
return ex - 0x3fff;
}
/*
* Pack an exponent and array of three doubles representing a finite,
* nonzero number into a quad. Assume the sign is already there and
* the rounding mode has been fudged accordingly.
*/
static void
union longdouble *x, int *inexact)
{
union {
double d;
unsigned int l[2];
} u;
/* bias exponent and strip off integer bit */
exp += 0x3fff;
s[0] = z[0] - one;
s[1] = z[1];
s[2] = z[2];
/*
* chop the significand to obtain the fraction;
* use round-to-minus-infinity to ensure chopping
*/
(void) __swapRD(fp_negative);
/* extract the first eighty bits of fraction */
t = s[1] + s[2];
u.d = two36 + (s[0] + t);
s[0] -= (u.d - two36);
u.d = two4 + (s[0] + t);
s[0] -= (u.d - two4);
u.d = twom28 + (s[0] + t);
s[0] -= (u.d - twom28);
/* condense the remaining fraction; errors here won't matter */
t = s[0] + s[1];
s[1] = ((s[0] - t) + s[1]) + s[2];
s[0] = t;
/* get the last word of fraction */
u.d = twom60 + (s[0] + s[1]);
s[0] -= (u.d - twom60);
/*
* keep track of what's left for rounding; note that
* t2 will be non-negative due to rounding mode
*/
t = s[0] + s[1];
t2 = (s[0] - t) + s[1];
if (t != zero)
{
*inexact = 1;
/* 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;
exp++;
}
}
}
/* assemble the result */
}
/*
* Compute the square root of x and place the TP result in s.
*/
static void
__q_tp_sqrt(const double *x, double *s)
{
/* approximate the divisor for the Newton iteration */
/* compute the first five "digits" of the square root */
tt[0] = t[0] + t[0];
r[0] = ((x[0] - t[0] * t[0]) + x[1]) + x[2];
r[0] -= tt[0] * t[1];
r[1] = x[3] - t[1] * t[1];
r[0] += c;
r[1] = (r[1] - c) + x[4];
r[0] -= tt[0] * t[2];
r[0] += c;
r[1] = (r[1] - c) - t[2] * t[2];
r[0] += c;
r[1] = (r[1] - c) - t[3] * t[3];
/* here we just need to get the sign of the remainder */
/* reduce to three doubles */
t[0] += t[1];
t[1] = t[2] + t[3];
t[2] = t[4];
/* if the third term might lie on a rounding boundary, perturb it */
{
if (c < zero)
t[2] -= twom124;
else
t[2] += twom124;
}
/* condense the square root */
c = t[1] + t[2];
t[2] += (t[1] - c);
t[1] = c;
c = t[0] + t[1];
s[1] = t[1] + (t[0] - c);
s[0] = c;
if (s[1] == zero)
{
c = s[0] + t[2];
s[1] = t[2] + (s[0] - c);
s[0] = c;
s[2] = zero;
}
else
{
c = s[1] + t[2];
s[2] = t[2] + (s[1] - c);
s[1] = c;
}
}
long double
{
union longdouble x;
volatile double t;
/* clear cexc */
t = zero;
t -= zero;
/* check for zero operand */
x.d = ldx;
return ldx;
/* handle nan and inf cases */
{
{
if (!(x.l.msw & 0x8000))
{
/* snan, signal invalid */
t += snan.d;
}
x.l.msw |= 0x8000;
return x.d;
}
if (x.l.msw & 0x80000000)
{
/* sqrt(-inf), signal invalid */
t = -one;
t = sqrt(t);
return qnan.d;
}
/* sqrt(inf), return inf */
return x.d;
}
/* handle negative numbers */
if (x.l.msw & 0x80000000)
{
t = -one;
t = sqrt(t);
return qnan.d;
}
/* now x is finite, positive */
if (ex & 1)
{
/* make exponent even */
ex--;
}
/* put everything together */
x.l.msw = 0;
inexact = 0;
if (inexact)
{
t = huge;
t += tiny;
}
return x.d;
}