/*
* 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.
*/
/*
* pow(x,y) return x**y
* n
* Method: Let x = 2 * (1+f)
* 1. Compute and return log2(x) in two pieces:
* log2(x) = w1 + w2,
* where w1 has 24 bits trailing zero.
* 2. Perform y*log2(x) by simulating muti-precision arithmetic
* 3. Return x**y = exp2(y*log(x))
*
* Special cases:
* 1. (anything) ** +-0 is 1
* 2. (anything) ** 1 is itself
* 3. (anything except 1) ** NAN is NAN ("except 1" is C99)
* 4. NAN ** (anything except 0) is NAN
* 5. +-(|x| > 1) ** +INF is +INF
* 6. +-(|x| > 1) ** -INF is +0
* 7. +-(|x| < 1) ** +INF is +0
* 8. +-(|x| < 1) ** -INF is +INF
* 9. -1 ** +-INF is 1 (C99; -1 ** +-INF used to be NAN)
* 10. +0 ** (+anything except 0, NAN) is +0
* 11. -0 ** (+anything except 0, NAN, odd integer) is +0
* 12. +0 ** (-anything except 0, NAN) is +INF
* 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
* 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
* 15. +INF ** (+anything except 0,NAN) is +INF
* 16. +INF ** (-anything except 0,NAN) is +0
* 17. -INF ** (anything) = -0 ** (-anything)
* 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
* 19. (-anything except 0 and inf) ** (non-integer) is NAN
*
* Accuracy:
* pow(x,y) returns x**y nearly rounded. In particular
* pow(integer,integer)
* always returns the correct integer provided it is representable.
*/
#include "libm.h"
#include "xpg6.h" /* __xpg6 */
extern const double _TBL_log2_hi[], _TBL_log2_lo[];
static const double
static double
log2_x(double x, double *w) {
double f, s, z, qn, h, t;
int *px = (int *) &x;
int *pz = (int *) &z;
int i, j, ix, n;
n = 0;
double f1, v;
f = x - one;
*w = zero;
return (zero); /* log2(1)= +0 */
}
s = f * qn; /* |s|<2**-6 */
v = s * s;
h = (double) ((float) s);
f1 = (double) ((float) f);
/* s = h+t */
h *= B0_hi;
s = (double) ((float) (h + t));
*w = t - (s - h);
return (s);
}
x *= two53;
n = -53;
}
/* LARGE N */
i = ix + 0x1000;
f = x - z;
s = f * qn;
h = (double) ((float) s);
t = qn * ((f - (h + h) * z) - h * f);
j = (i >> 13) & 0x7f;
f = s * s;
s = n + _TBL_log2_hi[j];
h = qn + s;
t += _TBL_log2_lo[j] - ((h - s) - qn);
f = (double) ((float) (h + t));
*w = t - (f - h);
return (f);
}
extern const double _TBL_exp2_hi[], _TBL_exp2_lo[];
static const double /* poly app of 2^x-1 on [-1e-10,2^-7+1e-10] */
double
pow(double x, double y) {
double z, ax;
int *pz = (int *) &z;
else
z = one; /* x**+-0 = 1 */
return (z);
(__xpg6 & _C99SUSv3_pow) != 0)
return (one); /* C99: 1**anything = 1 */
return (x * y); /* +-NaN return x*y; + -> * for Cheetah */
/* includes Sun: 1**NaN = NaN */
/*
* determine if y is an odd int when x < 0
* yisint = 0 ... y is not an integer
* yisint = 1 ... y is an odd int
* yisint = 2 ... y is an even int
*/
yisint = 0;
if (sbx) {
if (ahy >= 0x43400000)
else if (ahy >= 0x3ff00000) {
if (k > 20) {
j = ly >> (52 - k);
if ((j << (52 - k)) == ly)
} else if (ly == 0) {
j = ahy >> (20 - k);
if ((j << (20 - k)) == ahy)
}
}
}
/* special value of y */
if (ly == 0) {
if ((__xpg6 & _C99SUSv3_pow) != 0)
return (one);
/* C99: (-1)**+-inf = 1 */
else
return (y - y);
/* Sun: (+-1)**+-inf = NaN */
} else if (ahx >= 0x3ff00000)
/* (|x|>1)**+,-inf = inf,0 */
else /* (|x|<1)**-,+inf = inf,0 */
}
if (sby != 0) { /* y is -1 */
if (x == zero) /* divided by zero */
return (_SVID_libm_err(x, y, 23));
lx) == 0) /* overflow */
return (_SVID_libm_err(x, y, 21));
else
return (one / x);
} else
return (x);
}
return (_SVID_libm_err(x, y, 21));
/* x*x overflow */
return (_SVID_libm_err(x, y, 22));
/* x*x underflow */
else
return (x * x);
}
if (hy == 0x3fe00000) {
0 || sbx == 1))
return (sqrt(x)); /* y is 0.5 and x > 0 */
}
}
/* special value of x */
if (lx == 0) {
/* x is +-0,+-inf,-1 */
z = ax;
if (sby == 1) {
z = one / z; /* z = |x|**y */
if (ahx == 0)
return (_SVID_libm_err(x, y, 23));
}
if (sbx == 1) {
z = _SVID_libm_err(x, y, 24);
/* neg**non-integral is NaN + invalid */
else if (yisint == 1)
z = -z; /* (x<0)**odd = -(|x|**odd) */
}
return (z);
}
}
/* (x<0)**(non-int) is NaN */
return (_SVID_libm_err(x, y, 24));
/* Now ax is finite, y is finite */
/* first compute log2(ax) = w1+w2, with 24 bits w1 */
/* split up y into y1+y2 and compute (y1+y2)*(w1+w2) */
ahy <= 0x38100000) {
/* no need to split if y is short or too large or too small */
} else {
y1 = (double) ((float) y);
}
if (j >= 0x40900000) { /* z >= 1024 */
else {
/* rounded to inf */
if (w2 >= -8.008566259537296567160e-17)
return (_SVID_libm_err(x, y, 21));
/* overflow */
}
} else if ((j & ~0x80000000) >= 0x4090cc00) { /* z <= -1075 */
else {
return (_SVID_libm_err(x, y, 22));
}
}
/*
* compute 2**(k+f[j]+g)
*/
j = k & 63;
w2 = _TBL_exp2_hi[j];
z += w2;
k >>= 6;
if (k < -1021)
z = scalbn(z, k);
else /* subnormal output */
z = -z; /* (-ve)**(odd int) */
return (z);
}