All Downloads are FREE. Search and download functionalities are using the official Maven repository.

math.CommonsAccurateMath Maven / Gradle / Ivy

There is a newer version: 0.9.5
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package math;

/**
 * Faster, more accurate, portable alternative to {@link Math} and
 * {@link StrictMath} for large scale computation.
 * 

* CommonsAccurateMath is a drop-in replacement for some methods from Math and * StrictMath. This means that for any method in Math (say {@code Math.exp(x)} * or {@code Math.cbrt(y)}) that is defined in CommonsAccurateMath, user can * directly change the class and use the methods as is (using * {@code CommonsAccurateMath.exp(x)} or {@code CommonsAccurateMath.cbrt(y)} in * the previous example). *

*

* CommonsAccurateMath speed is achieved by relying heavily on optimizing * compilers to native code present in many JVMs today and use of large tables. * The larger tables are lazily initialised on first use, so that the setup time * does not penalise methods that don't need them. *

*

* CommonsAccurateMath accuracy should be mostly independent of the JVM as it * relies only on IEEE-754 basic operations and on embedded tables. Almost all * operations are accurate to about 0.5 ulp throughout the domain range. This * statement, of course is only a rough global observed behavior, it is * not a guarantee for every double numbers input (see William * Kahan's Table Maker's Dilemma). *

* * @version $Id: FastMath.java 1462503 2013-03-29 15:48:27Z luc $ * @since 2.2 */ final class CommonsAccurateMath { /* * There are 52 bits in the mantissa of a double. For additional precision, * the code splits double numbers into two parts, by clearing the low order * 30 bits if possible, and then performs the arithmetic on each half * separately. */ /** * 0x40000000 - used to split a double into two parts, both with the low * order bits cleared. Equivalent to 2^30. */ private static final long HEX_40000000 = 0x40000000L; // 1073741824L /** * 2^52 - double numbers this large must be integral (no fraction) or NaN or * Infinite */ private static final double TWO_POWER_52 = 4503599627370496.0; /** 2^53 - double numbers this large must be even. */ private static final double TWO_POWER_53 = 2 * TWO_POWER_52; private static final boolean RECOMPUTE_TABLES_AT_RUNTIME = false; /** Index of exp(0) in the array of integer exponentials. */ static final int EXP_INT_TABLE_MAX_INDEX = 750; /** Length of the array of integer exponentials. */ static final int EXP_INT_TABLE_LEN = EXP_INT_TABLE_MAX_INDEX * 2; /** Logarithm table length. */ static final int LN_MANT_LEN = 1024; /** log(2) (high bits). */ private static final double LN_2_A = 0.693147063255310059; /** log(2) (low bits). */ private static final double LN_2_B = 1.17304635250823482e-7; /** Coefficients for log, when input 0.99 < x < 1.01. */ private static final double LN_QUICK_COEF[][] = { { 1.0, 5.669184079525E-24 }, { -0.25, -0.25 }, { 0.3333333134651184, 1.986821492305628E-8 }, { -0.25, -6.663542893624021E-14 }, { 0.19999998807907104, 1.1921056801463227E-8 }, { -0.1666666567325592, -7.800414592973399E-9 }, { 0.1428571343421936, 5.650007086920087E-9 }, { -0.12502530217170715, -7.44321345601866E-11 }, { 0.11113807559013367, 9.219544613762692E-9 }, }; /** Coefficients for log in the range of 1.0 < x < 1.0 + 2^-10. */ private static final double LN_HI_PREC_COEF[][] = { { 1.0, -6.032174644509064E-23 }, { -0.25, -0.25 }, { 0.3333333134651184, 1.9868161777724352E-8 }, { -0.2499999701976776, -2.957007209750105E-8 }, { 0.19999954104423523, 1.5830993332061267E-10 }, { -0.16624879837036133, -2.6033824355191673E-8 } }; /** Exponential fractions table length. */ static final int EXP_FRAC_TABLE_LEN = 1025; // 0, 1/1024, ... 1024/1024 /** StrictMath.log(Double.MAX_VALUE): {@value} */ private static final double LOG_MAX_VALUE = StrictMath .log(Double.MAX_VALUE); /** Table of 2^((n+2)/3) */ private static final double CBRTTWO[] = { 0.6299605249474366, 0.7937005259840998, 1.0, 1.2599210498948732, 1.5874010519681994 }; /** * Enclose large data table in nested static class so it's only loaded on * first access. */ private static final class ExpIntTable { /** * Exponential evaluated at integer values, exp(x) = expIntTableA[x + * EXP_INT_TABLE_MAX_INDEX] + expIntTableB[x+EXP_INT_TABLE_MAX_INDEX]. */ private static final double[] EXP_INT_TABLE_A; /** * Exponential evaluated at integer values, exp(x) = expIntTableA[x + * EXP_INT_TABLE_MAX_INDEX] + expIntTableB[x+EXP_INT_TABLE_MAX_INDEX] */ private static final double[] EXP_INT_TABLE_B; static { if (RECOMPUTE_TABLES_AT_RUNTIME) { EXP_INT_TABLE_A = new double[CommonsAccurateMath.EXP_INT_TABLE_LEN]; EXP_INT_TABLE_B = new double[CommonsAccurateMath.EXP_INT_TABLE_LEN]; final double tmp[] = new double[2]; final double recip[] = new double[2]; // Populate expIntTable for (int i = 0; i < CommonsAccurateMath.EXP_INT_TABLE_MAX_INDEX; i++) { CommonsCalc.expint(i, tmp); EXP_INT_TABLE_A[i + CommonsAccurateMath.EXP_INT_TABLE_MAX_INDEX] = tmp[0]; EXP_INT_TABLE_B[i + CommonsAccurateMath.EXP_INT_TABLE_MAX_INDEX] = tmp[1]; if (i != 0) { // Negative integer powers CommonsCalc.splitReciprocal(tmp, recip); EXP_INT_TABLE_A[CommonsAccurateMath.EXP_INT_TABLE_MAX_INDEX - i] = recip[0]; EXP_INT_TABLE_B[CommonsAccurateMath.EXP_INT_TABLE_MAX_INDEX - i] = recip[1]; } } } else { EXP_INT_TABLE_A = CommonsMathLiterals.loadExpIntA(); EXP_INT_TABLE_B = CommonsMathLiterals.loadExpIntB(); } } } /** * Enclose large data table in nested static class so it's only loaded on * first access. */ private static final class ExpFracTable { /** * Exponential over the range of 0 - 1 in increments of 2^-10 * exp(x/1024) = expFracTableA[x] + expFracTableB[x]. 1024 = 2^10 */ private static final double[] EXP_FRAC_TABLE_A; /** * Exponential over the range of 0 - 1 in increments of 2^-10 * exp(x/1024) = expFracTableA[x] + expFracTableB[x]. */ private static final double[] EXP_FRAC_TABLE_B; static { if (RECOMPUTE_TABLES_AT_RUNTIME) { EXP_FRAC_TABLE_A = new double[CommonsAccurateMath.EXP_FRAC_TABLE_LEN]; EXP_FRAC_TABLE_B = new double[CommonsAccurateMath.EXP_FRAC_TABLE_LEN]; final double tmp[] = new double[2]; // Populate expFracTable final double factor = 1d / (EXP_FRAC_TABLE_LEN - 1); for (int i = 0; i < EXP_FRAC_TABLE_A.length; i++) { CommonsCalc.slowexp(i * factor, tmp); EXP_FRAC_TABLE_A[i] = tmp[0]; EXP_FRAC_TABLE_B[i] = tmp[1]; } } else { EXP_FRAC_TABLE_A = CommonsMathLiterals.loadExpFracA(); EXP_FRAC_TABLE_B = CommonsMathLiterals.loadExpFracB(); } } } /** * Enclose large data table in nested static class so it's only loaded on * first access. */ private static final class lnMant { /** * Extended precision logarithm table over the range 1 - 2 in increments * of 2^-10. */ private static final double[][] LN_MANT; static { if (RECOMPUTE_TABLES_AT_RUNTIME) { LN_MANT = new double[CommonsAccurateMath.LN_MANT_LEN][]; // Populate lnMant table for (int i = 0; i < LN_MANT.length; i++) { final double d = Double .longBitsToDouble((((long) i) << 42) | 0x3ff0000000000000L); LN_MANT[i] = CommonsCalc.slowLog(d); } } else { LN_MANT = CommonsMathLiterals.loadLnMant(); } } } /** * Power function. Compute x^y. * * @param x * a double * @param y * a double * @return double */ static double pow(double x, double y) { final double lns[] = new double[2]; if (y == 0.0) { return 1.0; } if (x != x) { // X is NaN return x; } if (x == 0) { long bits = Double.doubleToRawLongBits(x); if ((bits & 0x8000000000000000L) != 0) { // -zero long yi = (long) y; if (y < 0 && y == yi && (yi & 1) == 1) { return Double.NEGATIVE_INFINITY; } if (y > 0 && y == yi && (yi & 1) == 1) { return -0.0; } } if (y < 0) { return Double.POSITIVE_INFINITY; } if (y > 0) { return 0.0; } return Double.NaN; } if (x == Double.POSITIVE_INFINITY) { if (y != y) { // y is NaN return y; } if (y < 0.0) { return 0.0; } else { return Double.POSITIVE_INFINITY; } } if (y == Double.POSITIVE_INFINITY) { if (x * x == 1.0) { return Double.NaN; } if (x * x > 1.0) { return Double.POSITIVE_INFINITY; } else { return 0.0; } } if (x == Double.NEGATIVE_INFINITY) { if (y != y) { // y is NaN return y; } if (y < 0) { long yi = (long) y; if (y == yi && (yi & 1) == 1) { return -0.0; } return 0.0; } if (y > 0) { long yi = (long) y; if (y == yi && (yi & 1) == 1) { return Double.NEGATIVE_INFINITY; } return Double.POSITIVE_INFINITY; } } if (y == Double.NEGATIVE_INFINITY) { if (x * x == 1.0) { return Double.NaN; } if (x * x < 1.0) { return Double.POSITIVE_INFINITY; } else { return 0.0; } } /* Handle special case x<0 */ if (x < 0) { // y is an even integer in this case if (y >= TWO_POWER_53 || y <= -TWO_POWER_53) { return pow(-x, y); } if (y == (long) y) { // If y is an integer return ((long) y & 1) == 0 ? pow(-x, y) : -pow(-x, y); } else { return Double.NaN; } } /* Split y into ya and yb such that y = ya+yb */ double ya; double yb; if (y < 8e298 && y > -8e298) { double tmp1 = y * HEX_40000000; ya = y + tmp1 - tmp1; yb = y - ya; } else { double tmp1 = y * 9.31322574615478515625E-10; double tmp2 = tmp1 * 9.31322574615478515625E-10; ya = (tmp1 + tmp2 - tmp1) * HEX_40000000 * HEX_40000000; yb = y - ya; } /* Compute ln(x) */ final double lores = log_(x, lns); if (Double.isInfinite(lores)) { // don't allow this to be converted to // NaN return lores; } double lna = lns[0]; double lnb = lns[1]; /* resplit lns */ double tmp1 = lna * HEX_40000000; double tmp2 = lna + tmp1 - tmp1; lnb += lna - tmp2; lna = tmp2; // y*ln(x) = (aa+ab) final double aa = lna * ya; final double ab = lna * yb + lnb * ya + lnb * yb; lna = aa + ab; lnb = -(lna - aa - ab); double z = 1.0 / 120.0; z = z * lnb + (1.0 / 24.0); z = z * lnb + (1.0 / 6.0); z = z * lnb + 0.5; z = z * lnb + 1.0; z = z * lnb; final double result = exp_(lna, z, null); // result = result + result * z; return result; } /** * Raise a double to an int power. * * @param d * Number to raise. * @param e * Exponent. * @return de * @since 3.1 */ @SuppressWarnings("unused") private static double pow_(double d, int e) { if (e == 0) { return 1.0; } else if (e < 0) { e = -e; d = 1.0 / d; } // split d as two 26 bits numbers // beware the following expressions must NOT be simplified, they rely on // floating point arithmetic properties final int splitFactor = 0x8000001; final double cd = splitFactor * d; final double d1High = cd - (cd - d); final double d1Low = d - d1High; // prepare result double resultHigh = 1; double resultLow = 0; // d^(2p) double d2p = d; double d2pHigh = d1High; double d2pLow = d1Low; while (e != 0) { if ((e & 0x1) != 0) { // accurate multiplication result = result * d^(2p) using // Veltkamp TwoProduct algorithm // beware the following expressions must NOT be simplified, they // rely on floating point arithmetic properties final double tmpHigh = resultHigh * d2p; final double cRH = splitFactor * resultHigh; final double rHH = cRH - (cRH - resultHigh); final double rHL = resultHigh - rHH; final double tmpLow = rHL * d2pLow - (((tmpHigh - rHH * d2pHigh) - rHL * d2pHigh) - rHH * d2pLow); resultHigh = tmpHigh; resultLow = resultLow * d2p + tmpLow; } // accurate squaring d^(2(p+1)) = d^(2p) * d^(2p) using Veltkamp // TwoProduct algorithm // beware the following expressions must NOT be simplified, they // rely on floating point arithmetic properties final double tmpHigh = d2pHigh * d2p; final double cD2pH = splitFactor * d2pHigh; final double d2pHH = cD2pH - (cD2pH - d2pHigh); final double d2pHL = d2pHigh - d2pHH; final double tmpLow = d2pHL * d2pLow - (((tmpHigh - d2pHH * d2pHigh) - d2pHL * d2pHigh) - d2pHH * d2pLow); final double cTmpH = splitFactor * tmpHigh; d2pHigh = cTmpH - (cTmpH - tmpHigh); d2pLow = d2pLow * d2p + tmpLow + (tmpHigh - d2pHigh); d2p = d2pHigh + d2pLow; e = e >> 1; } return resultHigh + resultLow; } /** * Exponential function. * * Computes exp(x), function result is nearly rounded. It will be correctly * rounded to the theoretical value for 99.9% of input values, otherwise it * will have a 1 UPL error. * * Method: Lookup intVal = exp(int(x)) Lookup fracVal = exp(int(x-int(x) / * 1024.0) * 1024.0 ); Compute z as the exponential of the remaining bits by * a polynomial minus one exp(x) = intVal * fracVal * (1 + z) * * Accuracy: Calculation is done with 63 bits of precision, so result should * be correctly rounded for 99.9% of input values, with less than 1 ULP * error otherwise. * * @param x * a double * @return double ex */ static double exp(double x) { return exp_(x, 0.0, null); } /** * Internal helper method for exponential function. * * @param x * original argument of the exponential function * @param extra * extra bits of precision on input (To Be Confirmed) * @param hiPrec * extra bits of precision on output (To Be Confirmed) * @return exp(x) */ private static double exp_(double x, double extra, double[] hiPrec) { double intPartA; double intPartB; int intVal; /* * Lookup exp(floor(x)). intPartA will have the upper 22 bits, intPartB * will have the lower 52 bits. */ if (x < 0.0) { intVal = (int) -x; if (intVal > 746) { if (hiPrec != null) { hiPrec[0] = 0.0; hiPrec[1] = 0.0; } return 0.0; } if (intVal > 709) { /* This will produce a subnormal output */ final double result = exp_(x + 40.19140625, extra, hiPrec) / 285040095144011776.0; if (hiPrec != null) { hiPrec[0] /= 285040095144011776.0; hiPrec[1] /= 285040095144011776.0; } return result; } if (intVal == 709) { /* exp(1.494140625) is nearly a machine number... */ final double result = exp_(x + 1.494140625, extra, hiPrec) / 4.455505956692756620; if (hiPrec != null) { hiPrec[0] /= 4.455505956692756620; hiPrec[1] /= 4.455505956692756620; } return result; } intVal++; intPartA = ExpIntTable.EXP_INT_TABLE_A[EXP_INT_TABLE_MAX_INDEX - intVal]; intPartB = ExpIntTable.EXP_INT_TABLE_B[EXP_INT_TABLE_MAX_INDEX - intVal]; intVal = -intVal; } else { intVal = (int) x; if (intVal > 709) { if (hiPrec != null) { hiPrec[0] = Double.POSITIVE_INFINITY; hiPrec[1] = 0.0; } return Double.POSITIVE_INFINITY; } intPartA = ExpIntTable.EXP_INT_TABLE_A[EXP_INT_TABLE_MAX_INDEX + intVal]; intPartB = ExpIntTable.EXP_INT_TABLE_B[EXP_INT_TABLE_MAX_INDEX + intVal]; } /* * Get the fractional part of x, find the greatest multiple of 2^-10 * less than x and look up the exp function of it. fracPartA will have * the upper 22 bits, fracPartB the lower 52 bits. */ final int intFrac = (int) ((x - intVal) * 1024.0); final double fracPartA = ExpFracTable.EXP_FRAC_TABLE_A[intFrac]; final double fracPartB = ExpFracTable.EXP_FRAC_TABLE_B[intFrac]; /* * epsilon is the difference in x from the nearest multiple of 2^-10. It * has a value in the range 0 <= epsilon < 2^-10. Do the subtraction * from x as the last step to avoid possible loss of precision. */ final double epsilon = x - (intVal + intFrac / 1024.0); /* * Compute z = exp(epsilon) - 1.0 via a minimax polynomial. z has full * double precision (52 bits). Since z < 2^-10, we will have 62 bits of * precision when combined with the constant 1. This will be used in the * last addition below to get proper rounding. */ /* * Remez generated polynomial. Converges on the interval [0, 2^-10], * error is less than 0.5 ULP */ double z = 0.04168701738764507; z = z * epsilon + 0.1666666505023083; z = z * epsilon + 0.5000000000042687; z = z * epsilon + 1.0; z = z * epsilon + -3.940510424527919E-20; /* * Compute (intPartA+intPartB) * (fracPartA+fracPartB) by binomial * expansion. tempA is exact since intPartA and intPartB only have 22 * bits each. tempB will have 52 bits of precision. */ double tempA = intPartA * fracPartA; double tempB = intPartA * fracPartB + intPartB * fracPartA + intPartB * fracPartB; /* * Compute the result. (1+z)(tempA+tempB). Order of operations is * important. For accuracy add by increasing size. tempA is exact and * much larger than the others. If there are extra bits specified from * the pow() function, use them. */ final double tempC = tempB + tempA; final double result; if (extra != 0.0) { result = tempC * extra * z + tempC * extra + tempC * z + tempB + tempA; } else { result = tempC * z + tempB + tempA; } if (hiPrec != null) { // If requesting high precision hiPrec[0] = tempA; hiPrec[1] = tempC * extra * z + tempC * extra + tempC * z + tempB; } return result; } /** * Compute exp(x) - 1 * * @param x * number to compute shifted exponential * @return exp(x) - 1 */ static double expm1(double x) { return expm1_(x, null); } /** * Internal helper method for expm1 * * @param x * number to compute shifted exponential * @param hiPrecOut * receive high precision result for -1.0 < x < 1.0 * @return exp(x) - 1 */ private static double expm1_(double x, double hiPrecOut[]) { if (x != x || x == 0.0) { // NaN or zero return x; } if (x <= -1.0 || x >= 1.0) { // If not between +/- 1.0 // return exp(x) - 1.0; double hiPrec[] = new double[2]; exp_(x, 0.0, hiPrec); if (x > 0.0) { return -1.0 + hiPrec[0] + hiPrec[1]; } else { final double ra = -1.0 + hiPrec[0]; double rb = -(ra + 1.0 - hiPrec[0]); rb += hiPrec[1]; return ra + rb; } } double baseA; double baseB; double epsilon; boolean negative = false; if (x < 0.0) { x = -x; negative = true; } { int intFrac = (int) (x * 1024.0); double tempA = ExpFracTable.EXP_FRAC_TABLE_A[intFrac] - 1.0; double tempB = ExpFracTable.EXP_FRAC_TABLE_B[intFrac]; double temp = tempA + tempB; tempB = -(temp - tempA - tempB); tempA = temp; temp = tempA * HEX_40000000; baseA = tempA + temp - temp; baseB = tempB + (tempA - baseA); epsilon = x - intFrac / 1024.0; } /* Compute expm1(epsilon) */ double zb = 0.008336750013465571; zb = zb * epsilon + 0.041666663879186654; zb = zb * epsilon + 0.16666666666745392; zb = zb * epsilon + 0.49999999999999994; zb = zb * epsilon; zb = zb * epsilon; double za = epsilon; double temp = za + zb; zb = -(temp - za - zb); za = temp; temp = za * HEX_40000000; temp = za + temp - temp; zb += za - temp; za = temp; /* * Combine the parts. expm1(a+b) = expm1(a) + expm1(b) + * expm1(a)*expm1(b) */ double ya = za * baseA; // double yb = za*baseB + zb*baseA + zb*baseB; temp = ya + za * baseB; double yb = -(temp - ya - za * baseB); ya = temp; temp = ya + zb * baseA; yb += -(temp - ya - zb * baseA); ya = temp; temp = ya + zb * baseB; yb += -(temp - ya - zb * baseB); ya = temp; // ya = ya + za + baseA; // yb = yb + zb + baseB; temp = ya + baseA; yb += -(temp - baseA - ya); ya = temp; temp = ya + za; // yb += (ya > za) ? -(temp - ya - za) : -(temp - za - ya); yb += -(temp - ya - za); ya = temp; temp = ya + baseB; // yb += (ya > baseB) ? -(temp - ya - baseB) : -(temp - baseB - ya); yb += -(temp - ya - baseB); ya = temp; temp = ya + zb; // yb += (ya > zb) ? -(temp - ya - zb) : -(temp - zb - ya); yb += -(temp - ya - zb); ya = temp; if (negative) { /* Compute expm1(-x) = -expm1(x) / (expm1(x) + 1) */ double denom = 1.0 + ya; double denomr = 1.0 / denom; double denomb = -(denom - 1.0 - ya) + yb; double ratio = ya * denomr; temp = ratio * HEX_40000000; final double ra = ratio + temp - temp; double rb = ratio - ra; temp = denom * HEX_40000000; za = denom + temp - temp; zb = denom - za; rb += (ya - za * ra - za * rb - zb * ra - zb * rb) * denomr; // f(x) = x/1+x // Compute f'(x) // Product rule: d(uv) = du*v + u*dv // Chain rule: d(f(g(x)) = f'(g(x))*f(g'(x)) // d(1/x) = -1/(x*x) // d(1/1+x) = -1/( (1+x)^2) * 1 = -1/((1+x)*(1+x)) // d(x/1+x) = -x/((1+x)(1+x)) + 1/1+x = 1 / ((1+x)(1+x)) // Adjust for yb rb += yb * denomr; // numerator rb += -ya * denomb * denomr * denomr; // denominator // negate ya = -ra; yb = -rb; } if (hiPrecOut != null) { hiPrecOut[0] = ya; hiPrecOut[1] = yb; } return ya + yb; } /** * Compute the hyperbolic cosine of a number. * * @param x * number on which evaluation is done * @return hyperbolic cosine of x */ static double cosh(double x) { if (x != x) { return x; } // cosh[z] = (exp(z) + exp(-z))/2 // for numbers with magnitude 20 or so, // exp(-z) can be ignored in comparison with exp(z) if (x > 20) { if (x >= LOG_MAX_VALUE) { // Avoid overflow (MATH-905). final double t = exp(0.5 * x); return (0.5 * t) * t; } else { return 0.5 * exp(x); } } else if (x < -20) { if (x <= -LOG_MAX_VALUE) { // Avoid overflow (MATH-905). final double t = exp(-0.5 * x); return (0.5 * t) * t; } else { return 0.5 * exp(-x); } } final double hiPrec[] = new double[2]; if (x < 0.0) { x = -x; } exp_(x, 0.0, hiPrec); double ya = hiPrec[0] + hiPrec[1]; double yb = -(ya - hiPrec[0] - hiPrec[1]); double temp = ya * HEX_40000000; double yaa = ya + temp - temp; double yab = ya - yaa; // recip = 1/y double recip = 1.0 / ya; temp = recip * HEX_40000000; double recipa = recip + temp - temp; double recipb = recip - recipa; // Correct for rounding in division recipb += (1.0 - yaa * recipa - yaa * recipb - yab * recipa - yab * recipb) * recip; // Account for yb recipb += -yb * recip * recip; // y = y + 1/y temp = ya + recipa; yb += -(temp - ya - recipa); ya = temp; temp = ya + recipb; yb += -(temp - ya - recipb); ya = temp; double result = ya + yb; result *= 0.5; return result; } /** * Compute the hyperbolic sine of a number. * * @param x * number on which evaluation is done * @return hyperbolic sine of x */ static double sinh(double x) { boolean negate = false; if (x != x) { return x; } // sinh[z] = (exp(z) - exp(-z) / 2 // for values of z larger than about 20, // exp(-z) can be ignored in comparison with exp(z) if (x > 20) { if (x >= LOG_MAX_VALUE) { // Avoid overflow (MATH-905). final double t = exp(0.5 * x); return (0.5 * t) * t; } else { return 0.5 * exp(x); } } else if (x < -20) { if (x <= -LOG_MAX_VALUE) { // Avoid overflow (MATH-905). final double t = exp(-0.5 * x); return (-0.5 * t) * t; } else { return -0.5 * exp(-x); } } if (x == 0) { return x; } if (x < 0.0) { x = -x; negate = true; } double result; if (x > 0.25) { double hiPrec[] = new double[2]; exp_(x, 0.0, hiPrec); double ya = hiPrec[0] + hiPrec[1]; double yb = -(ya - hiPrec[0] - hiPrec[1]); double temp = ya * HEX_40000000; double yaa = ya + temp - temp; double yab = ya - yaa; // recip = 1/y double recip = 1.0 / ya; temp = recip * HEX_40000000; double recipa = recip + temp - temp; double recipb = recip - recipa; // Correct for rounding in division recipb += (1.0 - yaa * recipa - yaa * recipb - yab * recipa - yab * recipb) * recip; // Account for yb recipb += -yb * recip * recip; recipa = -recipa; recipb = -recipb; // y = y + 1/y temp = ya + recipa; yb += -(temp - ya - recipa); ya = temp; temp = ya + recipb; yb += -(temp - ya - recipb); ya = temp; result = ya + yb; result *= 0.5; } else { double hiPrec[] = new double[2]; expm1_(x, hiPrec); double ya = hiPrec[0] + hiPrec[1]; double yb = -(ya - hiPrec[0] - hiPrec[1]); /* Compute expm1(-x) = -expm1(x) / (expm1(x) + 1) */ double denom = 1.0 + ya; double denomr = 1.0 / denom; double denomb = -(denom - 1.0 - ya) + yb; double ratio = ya * denomr; double temp = ratio * HEX_40000000; double ra = ratio + temp - temp; double rb = ratio - ra; temp = denom * HEX_40000000; double za = denom + temp - temp; double zb = denom - za; rb += (ya - za * ra - za * rb - zb * ra - zb * rb) * denomr; // Adjust for yb rb += yb * denomr; // numerator rb += -ya * denomb * denomr * denomr; // denominator // y = y - 1/y temp = ya + ra; yb += -(temp - ya - ra); ya = temp; temp = ya + rb; yb += -(temp - ya - rb); ya = temp; result = ya + yb; result *= 0.5; } if (negate) { result = -result; } return result; } /** * Compute the hyperbolic tangent of a number. * * @param x * number on which evaluation is done * @return hyperbolic tangent of x */ static double tanh(double x) { boolean negate = false; if (x != x) { return x; } // tanh[z] = sinh[z] / cosh[z] // = (exp(z) - exp(-z)) / (exp(z) + exp(-z)) // = (exp(2x) - 1) / (exp(2x) + 1) // for magnitude > 20, sinh[z] == cosh[z] in double precision if (x > 20.0) { return 1.0; } if (x < -20) { return -1.0; } if (x == 0) { return x; } if (x < 0.0) { x = -x; negate = true; } double result; if (x >= 0.5) { double hiPrec[] = new double[2]; // tanh(x) = (exp(2x) - 1) / (exp(2x) + 1) exp_(x * 2.0, 0.0, hiPrec); double ya = hiPrec[0] + hiPrec[1]; double yb = -(ya - hiPrec[0] - hiPrec[1]); /* Numerator */ double na = -1.0 + ya; double nb = -(na + 1.0 - ya); double temp = na + yb; nb += -(temp - na - yb); na = temp; /* Denominator */ double da = 1.0 + ya; double db = -(da - 1.0 - ya); temp = da + yb; db += -(temp - da - yb); da = temp; temp = da * HEX_40000000; double daa = da + temp - temp; double dab = da - daa; // ratio = na/da double ratio = na / da; temp = ratio * HEX_40000000; double ratioa = ratio + temp - temp; double ratiob = ratio - ratioa; // Correct for rounding in division ratiob += (na - daa * ratioa - daa * ratiob - dab * ratioa - dab * ratiob) / da; // Account for nb ratiob += nb / da; // Account for db ratiob += -db * na / da / da; result = ratioa + ratiob; } else { double hiPrec[] = new double[2]; // tanh(x) = expm1(2x) / (expm1(2x) + 2) expm1_(x * 2.0, hiPrec); double ya = hiPrec[0] + hiPrec[1]; double yb = -(ya - hiPrec[0] - hiPrec[1]); /* Numerator */ double na = ya; double nb = yb; /* Denominator */ double da = 2.0 + ya; double db = -(da - 2.0 - ya); double temp = da + yb; db += -(temp - da - yb); da = temp; temp = da * HEX_40000000; double daa = da + temp - temp; double dab = da - daa; // ratio = na/da double ratio = na / da; temp = ratio * HEX_40000000; double ratioa = ratio + temp - temp; double ratiob = ratio - ratioa; // Correct for rounding in division ratiob += (na - daa * ratioa - daa * ratiob - dab * ratioa - dab * ratiob) / da; // Account for nb ratiob += nb / da; // Account for db ratiob += -db * na / da / da; result = ratioa + ratiob; } if (negate) { result = -result; } return result; } /** * Compute the cubic root of a number. * * @param x * number on which evaluation is done * @return cubic root of x */ static double cbrt(double x) { /* Convert input double to bits */ long inbits = Double.doubleToRawLongBits(x); int exponent = (int) ((inbits >> 52) & 0x7ff) - 1023; boolean subnormal = false; if (exponent == -1023) { if (x == 0) { return x; } /* Subnormal, so normalize */ subnormal = true; x *= 1.8014398509481984E16; // 2^54 inbits = Double.doubleToRawLongBits(x); exponent = (int) ((inbits >> 52) & 0x7ff) - 1023; } if (exponent == 1024) { // Nan or infinity. Don't care which. return x; } /* Divide the exponent by 3 */ int exp3 = exponent / 3; /* p2 will be the nearest power of 2 to x with its exponent divided by 3 */ double p2 = Double.longBitsToDouble((inbits & 0x8000000000000000L) | (long) (((exp3 + 1023) & 0x7ff)) << 52); /* This will be a number between 1 and 2 */ final double mant = Double .longBitsToDouble((inbits & 0x000fffffffffffffL) | 0x3ff0000000000000L); /* Estimate the cube root of mant by polynomial */ double est = -0.010714690733195933; est = est * mant + 0.0875862700108075; est = est * mant + -0.3058015757857271; est = est * mant + 0.7249995199969751; est = est * mant + 0.5039018405998233; est *= CBRTTWO[exponent % 3 + 2]; // est should now be good to about 15 bits of precision. Do 2 rounds of // Newton's method to get closer, this should get us full double // precision // Scale down x for the purpose of doing newtons method. This avoids // over/under flows. final double xs = x / (p2 * p2 * p2); est += (xs - est * est * est) / (3 * est * est); est += (xs - est * est * est) / (3 * est * est); // Do one round of Newton's method in extended precision to get the last // bit right. double temp = est * HEX_40000000; double ya = est + temp - temp; double yb = est - ya; double za = ya * ya; double zb = ya * yb * 2.0 + yb * yb; temp = za * HEX_40000000; double temp2 = za + temp - temp; zb += za - temp2; za = temp2; zb = za * yb + ya * zb + zb * yb; za = za * ya; double na = xs - za; double nb = -(na - xs + za); nb -= zb; est += (na + nb) / (3 * est * est); /* Scale by a power of two, so this is exact. */ est *= p2; if (subnormal) { est *= 3.814697265625E-6; // 2^-18 } return est; } /** * Internal helper method for natural logarithm function. * * @param x * original argument of the natural logarithm function * @param hiPrec * extra bits of precision on output (To Be Confirmed) * @return log(x) */ private static double log_(final double x, final double[] hiPrec) { if (x == 0) { // Handle special case of +0/-0 return Double.NEGATIVE_INFINITY; } long bits = Double.doubleToRawLongBits(x); /* Handle special cases of negative input, and NaN */ if (((bits & 0x8000000000000000L) != 0 || x != x) && x != 0.0) { if (hiPrec != null) { hiPrec[0] = Double.NaN; } return Double.NaN; } /* Handle special cases of Positive infinity. */ if (x == Double.POSITIVE_INFINITY) { if (hiPrec != null) { hiPrec[0] = Double.POSITIVE_INFINITY; } return Double.POSITIVE_INFINITY; } /* Extract the exponent */ int exp = (int) (bits >> 52) - 1023; if ((bits & 0x7ff0000000000000L) == 0) { // Subnormal! if (x == 0) { // Zero if (hiPrec != null) { hiPrec[0] = Double.NEGATIVE_INFINITY; } return Double.NEGATIVE_INFINITY; } /* Normalize the subnormal number. */ bits <<= 1; while ((bits & 0x0010000000000000L) == 0) { --exp; bits <<= 1; } } if ((exp == -1 || exp == 0) && x < 1.01 && x > 0.99 && hiPrec == null) { /* * The normal method doesn't work well in the range [0.99, 1.01], so * call do a straight polynomial expansion in higer precision. */ /* Compute x - 1.0 and split it */ double xa = x - 1.0; double xb = xa - x + 1.0; double tmp = xa * HEX_40000000; double aa = xa + tmp - tmp; double ab = xa - aa; xa = aa; xb = ab; final double[] lnCoef_last = LN_QUICK_COEF[LN_QUICK_COEF.length - 1]; double ya = lnCoef_last[0]; double yb = lnCoef_last[1]; for (int i = LN_QUICK_COEF.length - 2; i >= 0; i--) { /* Multiply a = y * x */ aa = ya * xa; ab = ya * xb + yb * xa + yb * xb; /* split, so now y = a */ tmp = aa * HEX_40000000; ya = aa + tmp - tmp; yb = aa - ya + ab; /* Add a = y + lnQuickCoef */ final double[] lnCoef_i = LN_QUICK_COEF[i]; aa = ya + lnCoef_i[0]; ab = yb + lnCoef_i[1]; /* Split y = a */ tmp = aa * HEX_40000000; ya = aa + tmp - tmp; yb = aa - ya + ab; } /* Multiply a = y * x */ aa = ya * xa; ab = ya * xb + yb * xa + yb * xb; /* split, so now y = a */ tmp = aa * HEX_40000000; ya = aa + tmp - tmp; yb = aa - ya + ab; return ya + yb; } // lnm is a log of a number in the range of 1.0 - 2.0, so 0 <= lnm < // ln(2) final double[] lnm = lnMant.LN_MANT[(int) ((bits & 0x000ffc0000000000L) >> 42)]; /* * double epsilon = x / Double.longBitsToDouble(bits & * 0xfffffc0000000000L); * * epsilon -= 1.0; */ // y is the most significant 10 bits of the mantissa // double y = Double.longBitsToDouble(bits & 0xfffffc0000000000L); // double epsilon = (x - y) / y; final double epsilon = (bits & 0x3ffffffffffL) / (TWO_POWER_52 + (bits & 0x000ffc0000000000L)); double lnza = 0.0; double lnzb = 0.0; if (hiPrec != null) { /* split epsilon -> x */ double tmp = epsilon * HEX_40000000; double aa = epsilon + tmp - tmp; double ab = epsilon - aa; double xa = aa; double xb = ab; /* Need a more accurate epsilon, so adjust the division. */ final double numer = bits & 0x3ffffffffffL; final double denom = TWO_POWER_52 + (bits & 0x000ffc0000000000L); aa = numer - xa * denom - xb * denom; xb += aa / denom; /* Remez polynomial evaluation */ final double[] lnCoef_last = LN_HI_PREC_COEF[LN_HI_PREC_COEF.length - 1]; double ya = lnCoef_last[0]; double yb = lnCoef_last[1]; for (int i = LN_HI_PREC_COEF.length - 2; i >= 0; i--) { /* Multiply a = y * x */ aa = ya * xa; ab = ya * xb + yb * xa + yb * xb; /* split, so now y = a */ tmp = aa * HEX_40000000; ya = aa + tmp - tmp; yb = aa - ya + ab; /* Add a = y + lnHiPrecCoef */ final double[] lnCoef_i = LN_HI_PREC_COEF[i]; aa = ya + lnCoef_i[0]; ab = yb + lnCoef_i[1]; /* Split y = a */ tmp = aa * HEX_40000000; ya = aa + tmp - tmp; yb = aa - ya + ab; } /* Multiply a = y * x */ aa = ya * xa; ab = ya * xb + yb * xa + yb * xb; /* split, so now lnz = a */ /* * tmp = aa * 1073741824.0; lnza = aa + tmp - tmp; lnzb = aa - lnza * + ab; */ lnza = aa + ab; lnzb = -(lnza - aa - ab); } else { /* * High precision not required. Eval Remez polynomial using standard * double precision */ lnza = -0.16624882440418567; lnza = lnza * epsilon + 0.19999954120254515; lnza = lnza * epsilon + -0.2499999997677497; lnza = lnza * epsilon + 0.3333333333332802; lnza = lnza * epsilon + -0.5; lnza = lnza * epsilon + 1.0; lnza = lnza * epsilon; } /* * Relative sizes: lnzb [0, 2.33E-10] lnm[1] [0, 1.17E-7] ln2B*exp [0, * 1.12E-4] lnza [0, 9.7E-4] lnm[0] [0, 0.692] ln2A*exp [0, 709] */ /* * Compute the following sum: lnzb + lnm[1] + ln2B*exp + lnza + lnm[0] + * ln2A*exp; */ // return lnzb + lnm[1] + ln2B*exp + lnza + lnm[0] + ln2A*exp; double a = LN_2_A * exp; double b = 0.0; double c = a + lnm[0]; double d = -(c - a - lnm[0]); a = c; b = b + d; c = a + lnza; d = -(c - a - lnza); a = c; b = b + d; c = a + LN_2_B * exp; d = -(c - a - LN_2_B * exp); a = c; b = b + d; c = a + lnm[1]; d = -(c - a - lnm[1]); a = c; b = b + d; c = a + lnzb; d = -(c - a - lnzb); a = c; b = b + d; if (hiPrec != null) { hiPrec[0] = a; hiPrec[1] = b; } return a + b; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy