/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.internal; /** * Java port of fdlibm functions. */ public final class MathImpl { private MathImpl() { } /* @formatter:off */ private static final double log2e = 1.442695040888963407359924, /* 3FF71547 652B82FE */ two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ Lg7 = 1.479819860511658591e-01, /* 3FC2F112 DF3E5244 */ zero = 0d, /* 00000000 00000000 */ one = 1.0d, /* 3FF00000 00000000 */ two = 2.0, ln2 = Math.log(2d), /* 3FE62E42 FEFA39EF */ huge = 1e300, tiny = 1.0e-300, /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ private static final double[] bp = {1.0, 1.5,}, dp_h = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ dp_l = { 0.0, 1.35003920212974897128e-08,}; /* 0x3E4CFDEB, 0x43CFD006 */ /* @formatter:on */ /* @formatter:off */ /* @(#)e_log.c 1.3 95/01/18 */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunSoft, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ /** * Returns the base 2 logarithm of {@code x}. * <p> * This method computes {@code Math.log(x) / Math.log(2.0)}, but may yield better accuracy. * * @param x * a double value * @return the base 2 logarithm of {@code x} */ public static double log2(double x) { double hfsq,f,s,z,R,w,t1,t2,dk; int k,hx,i,j; /* unsigned */ int lx; long bits = Double.doubleToRawLongBits(x); hx = __HI(bits); /* high word of x */ lx = __LO(bits); /* low word of x */ k=0; if (hx < 0x00100000) { /* x < 2**-1022 */ if (((hx&0x7fffffff)|lx)==0) return -two54/zero; /* log(+-0)=-inf */ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ k -= 54; x *= two54; /* subnormal number, scale up x */ hx = __HI(x); /* high word of x */ } if (hx >= 0x7ff00000) return x+x; k += (hx>>20)-1023; hx &= 0x000fffff; i = (hx+0x95f64)&0x100000; x = __HI(x, hx|(i^0x3ff00000)); /* normalize x or x/2 */ k += (i>>20); f = x-1.0; if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */ if(f==zero) { if(k==0) return zero; dk=(double)k; return dk; } R = f*f*(0.5-0.33333333333333333*f); if(k==0) return (f - R) * log2e; dk=(double)k; return dk - (R - f) * log2e; } s = f/(2.0+f); dk = (double)k; z = s*s; i = hx-0x6147a; w = z*z; j = 0x6b851-hx; t1= w*(Lg2+w*(Lg4+w*Lg6)); t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); i |= j; R = t2+t1; if(i>0) { hfsq=0.5*f*f; if(k==0) return (f - (hfsq - s * (hfsq + R))) * log2e; return dk - (hfsq - s * (hfsq + R) - f) * log2e; } else { if(k==0) return (f - s * (f - R)) * log2e; return dk - (s * (f - R) - f) * log2e; } } /* @formatter:on */ /* @formatter:off */ /* @(#)e_acosh.c 1.3 95/01/18 */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunSoft, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== * */ /** * Returns the hyperbolic arc-cosine of {@code x}. * * @param x * a double value * @return the hyperbolic arc-cosine of {@code x} */ public static double acosh(final double x) { final long bits = Double.doubleToRawLongBits(x); final int hx = __HI(bits); if (hx < 0x3ff00000) { /* x < 1 */ return (x - x) / (x - x); } else if (hx >= 0x41b00000) { /* x > 2**28 */ if (hx >= 0x7ff00000) { /* x is inf of NaN */ return x + x; } else return Math.log(x) + ln2; /* acosh(huge)=log(2x) */ } else if (((hx - 0x3ff00000) | __LO(bits)) == 0) { return 0.0; /* acosh(1) = 0 */ } else if (hx > 0x40000000) { /* 2**28 > x > 2 */ final double t = x * x; return Math.log(2.0 * x - one / (x + Math.sqrt(t - one))); } else { /* 1<x<2 */ final double t = x - one; return Math.log1p(t + Math.sqrt(2.0 * t + t * t)); } } /* @formatter:on */ /* @formatter:off */ /* @(#)s_asinh.c 1.3 95/01/18 */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunSoft, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ /** * Returns the hyperbolic arc-sine of {@code x}. * * @param x * a double value * @return the hyperbolic arc-sine of {@code x} */ public static double asinh(final double x) { final long bits = Double.doubleToRawLongBits(x); final int hx = __HI(bits); final int ix = hx & 0x7fffffff; if (ix >= 0x7ff00000) return x + x; /* x is inf or NaN */ if (ix < 0x3e300000) { /* |x|<2**-28 */ if (huge + x > one) return x; /* return x inexact except 0 */ } final double w; if (ix > 0x41b00000) { /* |x| > 2**28 */ w = Math.log(Math.abs(x)) + ln2; } else if (ix > 0x40000000) { /* 2**28 > |x| > 2.0 */ final double t = Math.abs(x); w = Math.log(2.0 * t + one / (Math.sqrt(x * x + one) + t)); } else { /* 2.0 > |x| > 2**-28 */ final double t = x * x; w = Math.log1p(Math.abs(x) + t / (one + Math.sqrt(one + t))); } if (hx > 0) return w; else return -w; } /* @formatter:on */ /* @formatter:off */ /* @(#)e_atanh.c 1.3 95/01/18 */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunSoft, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== * */ /** * Returns the hyperbolic arc-tangent of {@code x}. * * @param x * a double value * @return the hyperbolic arc-tangent of {@code x} */ public static double atanh(double x) { final long bits = Double.doubleToRawLongBits(x); double t; final int hx = __HI(bits); /* high word */ final int lx = __LO(bits); /* low word */ final int ix = hx & 0x7fffffff; if ((ix | ((lx | (-lx)) >> 31)) > 0x3ff00000) /* |x|>1 */ return (x - x) / (x - x); if (ix == 0x3ff00000) return x / zero; if (ix < 0x3e300000 && (huge + x) > zero) return x; /* x<2**-28 */ x = toDouble(ix, lx); /* x <- |x| */ if (ix < 0x3fe00000) { /* x < 0.5 */ t = x + x; t = 0.5 * Math.log1p(t + t * x / (one - x)); } else t = 0.5 * Math.log1p((x + x) / (one - x)); if (hx >= 0) return t; else return -t; } /* @formatter:on */ /* @formatter:on */ /* @(#)e_pow.c 1.5 04/04/22 SMI */ /* * ==================================================== * 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 * is preserved. * ==================================================== */ public static double pow(double x, double y) { double z,ax,z_h,z_l,p_h,p_l; double y1,t1,t2,r,s,t,u,v,w; int i,j,k,yisint,n; int hx,hy,ix,iy; /*unsigned*/ int lx,ly; // int i0, i1; // i0 = ((*(int*)&one)>>29)^1; i1=1-i0; hx = __HI(x); lx = __LO(x); hy = __HI(y); ly = __LO(y); ix = hx&0x7fffffff; iy = hy&0x7fffffff; /* y==zero: x**0 = 1 */ if((iy|ly)==0) return one; /* +-NaN return x+y */ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) return x+y; /* 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(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); } 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 (iy==0x7ff00000) { /* y is +-inf */ if(((ix-0x3ff00000)|lx)==0) return y - y; /* inf**+-1 is NaN */ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ 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 Math.sqrt(x); } } ax = Math.abs(x); /* special value of x */ if(lx==0) { if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ z = ax; /*x is +-0,+-inf,+-1*/ if(hy<0) z = one/z; /* z = (1/|x|) */ if(hx<0) { if(((ix-0x3ff00000)|yisint)==0) { z = (z-z)/(z-z); /* (-1)**non-int is NaN */ } else if(yisint==1) z = -z; /* (x<0)**odd = -(|x|**odd) */ } return z; } } n = (hx>>31)+1; /* (x<0)**(non-int) is NaN */ if((n|yisint)==0) return (x-x)/(x-x); s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ /* |y| is huge */ if(iy>0x41e00000) { /* if |y| > 2**31 */ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; // Remove if-condition to pass FindBugs validation. // if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; return (hy>0)? huge*huge:tiny*tiny; } /* 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 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)); u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ v = t*ivln2_l-w*ivln2; t1 = u+v; // __LO(t1) = 0; t1 = __LO(t1, 0); t2 = v-(t1-u); } else { double ss,s2,s_h,s_l,t_h,t_l; n = 0; /* take care subnormal number */ if(ix<0x00100000) {ax *= two53; n -= 53; ix = __HI(ax); } n += ((ix)>>20)-0x3ff; j = ix&0x000fffff; /* determine interval */ ix = j|0x3ff00000; /* normalize ix */ if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */ else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */ else {k=0;n+=1;ix -= 0x00100000;} // __HI(ax) = ix; ax = __HI(ax, ix); /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ v = one/(ax+bp[k]); ss = u*v; s_h = ss; // __LO(s_h) = 0; s_h = __LO(s_h, 0); /* t_h=ax+bp[k] High */ t_h = zero; // __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); t_h = __HI(t_h, ((ix>>1)|0x20000000)+0x00080000+(k<<18)); t_l = ax - (t_h-bp[k]); s_l = v*((u-s_h*t_h)-s_h*t_l); /* compute log(ax) */ s2 = ss*ss; 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; // __LO(t_h) = 0; t_h = __LO(t_h, 0); t_l = r-((t_h-3.0)-s2); /* u+v = ss*(1+...) */ u = s_h*t_h; v = s_l*t_h+t_l*ss; /* 2/(3log2)*(ss+...) */ p_h = u+v; // __LO(p_h) = 0; p_h = __LO(p_h, 0); p_l = v-(p_h-u); 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; t1 = (((z_h+z_l)+dp_h[k])+t); // __LO(t1) = 0; t1 = __LO(t1, 0); t2 = z_l-(((t1-t)-dp_h[k])-z_h); } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ y1 = y; // __LO(y1) = 0; y1 = __LO(y1, 0); p_l = (y-y1)*t1+y*t2; p_h = y1*t1; z = p_l+p_h; j = __HI(z); i = __LO(z); if (j>=0x40900000) { /* z >= 1024 */ if(((j-0x40900000)|i)!=0) /* if z > 1024 */ return s*huge*huge; /* overflow */ else { if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ } } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ return s*tiny*tiny; /* underflow */ else { if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ } } /* * compute 2**(p_h+p_l) */ i = j&0x7fffffff; k = (i>>20)-0x3ff; n = 0; if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ n = j+(0x00100000>>(k+1)); k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ t = zero; // __HI(t) = (n&~(0x000fffff>>k)); t = __HI(t, (n&~(0x000fffff>>k))); n = ((n&0x000fffff)|0x00100000)>>(20-k); if(j<0) n = -n; p_h -= t; } t = p_l+p_h; // __LO(t) = 0; t = __LO(t, 0); u = t*lg2_h; v = (p_l-(t-p_h))*lg2+t*lg2_l; z = u+v; w = v-(z-u); t = z*z; t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); r = (z*t1)/(t1-two)-(w+z*w); z = one-(r-z); j = __HI(z); j += (n<<20); if((j>>20)<=0) z = Math.scalb(z,n); /* subnormal output */ // else __HI(z) += (n<<20); else z = __HI(z, __HI(z) + (n<<20)); return s*z; } /* @formatter:off */ private static int __HI(long bits) { return (int) (bits >>> 32); } private static int __LO(long bits) { return (int) bits; } private static int __HI(double value) { return __HI(Double.doubleToRawLongBits(value)); } private static int __LO(double value) { return __LO(Double.doubleToRawLongBits(value)); } private static double __HI(double value, int hi) { return Double.longBitsToDouble(((long) hi << 32) | ((long) __LO(value) & 0xFFFF_FFFFL)); } private static double __LO(double value, int lo) { return Double.longBitsToDouble(((long) __HI(value) << 32) | ((long) lo & 0xFFFF_FFFFL)); } private static double toDouble(int hi, int lo) { return Double.longBitsToDouble(((long) hi << 32) | ((long) lo & 0xFFFF_FFFFL)); } }