diff options
author | Matt A. Tobin <email@mattatobin.com> | 2019-11-15 17:37:54 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2019-11-15 17:37:54 -0500 |
commit | 556349010e01d0a3b7896f858d503781ea837b46 (patch) | |
tree | f003183732dc3cda4ad880407880da282ca4b0c5 /modules/fdlibm/src/e_pow.cpp | |
parent | f3d462c6049bd2f35571c2a0e2a7c4df4f3ca81c (diff) | |
parent | 3492ad65236209e741ca3641789efeaa22a6b8a4 (diff) | |
download | UXP-556349010e01d0a3b7896f858d503781ea837b46.tar UXP-556349010e01d0a3b7896f858d503781ea837b46.tar.gz UXP-556349010e01d0a3b7896f858d503781ea837b46.tar.lz UXP-556349010e01d0a3b7896f858d503781ea837b46.tar.xz UXP-556349010e01d0a3b7896f858d503781ea837b46.zip |
Merge branch 'master' into mailnews-work
Diffstat (limited to 'modules/fdlibm/src/e_pow.cpp')
-rw-r--r-- | modules/fdlibm/src/e_pow.cpp | 54 |
1 files changed, 30 insertions, 24 deletions
diff --git a/modules/fdlibm/src/e_pow.cpp b/modules/fdlibm/src/e_pow.cpp index 366e3933b..c18226b8a 100644 --- a/modules/fdlibm/src/e_pow.cpp +++ b/modules/fdlibm/src/e_pow.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. * * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice + * software is freely granted, provided that this notice * is preserved. * ==================================================== */ @@ -19,7 +19,7 @@ * 1. Compute and return log2(x) in two pieces: * log2(x) = w1 + w2, * where w1 has 53-24 = 29 bit trailing zeros. - * 2. Perform y*log2(x) = n+y' by simulating multi-precision + * 2. Perform y*log2(x) = n+y' by simulating multi-precision * arithmetic, where |y'|<=0.5. * 3. Return x**y = 2**n*exp(y'*log2) * @@ -47,16 +47,19 @@ * Accuracy: * pow(x,y) returns x**y nearly rounded. In particular * pow(integer,integer) - * always returns the correct integer provided it is + * always returns the correct integer provided it is * representable. * * Constants : - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. */ +#include <cmath> + +#include <float.h> #include "math_private.h" static const double @@ -64,6 +67,9 @@ bp[] = {1.0, 1.5,}, dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ zero = 0.0, +half = 0.5, +qrtr = 0.25, +thrd = 3.3333333333333331e-01, /* 0x3fd55555, 0x55555555 */ one = 1.0, two = 2.0, two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ @@ -106,15 +112,15 @@ __ieee754_pow(double x, double y) ix = hx&0x7fffffff; iy = hy&0x7fffffff; /* y==zero: x**0 = 1 */ - if((iy|ly)==0) return one; + if((iy|ly)==0) return one; /* x==1: 1**y = 1, even if y is NaN */ if (hx==0x3ff00000 && lx == 0) return one; /* y!=zero: result is NaN if either arg is NaN */ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || - iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) - return (x+0.0)+(y+0.0); + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return nan_mix(x, y); /* determine if y is an odd int when x < 0 * yisint = 0 ... y is not an integer @@ -122,22 +128,22 @@ __ieee754_pow(double x, double y) * yisint = 2 ... y is an even int */ yisint = 0; - if(hx<0) { + if(hx<0) { if(iy>=0x43400000) yisint = 2; /* even integer y */ else if(iy>=0x3ff00000) { k = (iy>>20)-0x3ff; /* exponent */ if(k>20) { j = ly>>(52-k); - if((j<<(52-k))==ly) yisint = 2-(j&1); + if(((u_int32_t)j<<(52-k))==ly) yisint = 2-(j&1); } else if(ly==0) { j = iy>>(20-k); if((j<<(20-k))==iy) yisint = 2-(j&1); } - } - } + } + } /* special value of y */ - if(ly==0) { + if(ly==0) { if (iy==0x7ff00000) { /* y is +-inf */ if(((ix-0x3ff00000)|lx)==0) return one; /* (-1)**+-inf is 1 */ @@ -145,14 +151,14 @@ __ieee754_pow(double x, double y) return (hy>=0)? y: zero; else /* (|x|<1)**-,+inf = inf,0 */ return (hy<0)?-y: zero; - } + } if(iy==0x3ff00000) { /* y is +-1 */ if(hy<0) return one/x; else return x; } if(hy==0x40000000) return x*x; /* y is 2 */ if(hy==0x3fe00000) { /* y is 0.5 */ if(hx>=0) /* x >= +0 */ - return sqrt(x); + return std::sqrt(x); } } @@ -165,13 +171,13 @@ __ieee754_pow(double x, double y) if(hx<0) { if(((ix-0x3ff00000)|yisint)==0) { z = (z-z)/(z-z); /* (-1)**non-int is NaN */ - } else if(yisint==1) + } else if(yisint==1) z = -z; /* (x<0)**odd = -(|x|**odd) */ } return z; } } - + /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be n = (hx>>31)+1; but ANSI C says a right shift of a signed negative quantity is @@ -193,10 +199,10 @@ __ieee754_pow(double x, double y) /* over/underflow if x is not close to one */ if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; - /* now |1-x| is tiny <= 2**-20, suffice to compute + /* now |1-x| is tiny <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax-one; /* t has 20 trailing zeros */ - w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + w = (t*t)*(half-t*(thrd-t*qrtr)); u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ v = t*ivln2_l-w*ivln2; t1 = u+v; @@ -233,9 +239,9 @@ __ieee754_pow(double x, double y) r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); r += s_l*(s_h+ss); s2 = s_h*s_h; - t_h = 3.0+s2+r; + t_h = 3+s2+r; SET_LOW_WORD(t_h,0); - t_l = r-((t_h-3.0)-s2); + t_l = r-((t_h-3)-s2); /* u+v = ss*(1+...) */ u = s_h*t_h; v = s_l*t_h+t_l*ss; @@ -246,7 +252,7 @@ __ieee754_pow(double x, double y) z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ z_l = cp_l*p_h+p_l*cp+dp_l[k]; /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = (double)n; + t = n; t1 = (((z_h+z_l)+dp_h[k])+t); SET_LOW_WORD(t1,0); t2 = z_l-(((t1-t)-dp_h[k])-z_h); @@ -286,7 +292,7 @@ __ieee754_pow(double x, double y) n = ((n&0x000fffff)|0x00100000)>>(20-k); if(j<0) n = -n; p_h -= t; - } + } t = p_l+p_h; SET_LOW_WORD(t,0); u = t*lg2_h; |