diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math/util/FastMath.java')
-rw-r--r-- | src/main/java/org/apache/commons/math/util/FastMath.java | 4047 |
1 files changed, 4047 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math/util/FastMath.java b/src/main/java/org/apache/commons/math/util/FastMath.java new file mode 100644 index 0000000..1907b32 --- /dev/null +++ b/src/main/java/org/apache/commons/math/util/FastMath.java @@ -0,0 +1,4047 @@ +/* + * 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 org.apache.commons.math.util; + +/** + * Faster, more accurate, portable alternative to {@link StrictMath}. + * <p> + * Additionally implements the following methods not found in StrictMath: + * <ul> + * <li>{@link #asinh(double)}</li> + * <li>{@link #acosh(double)}</li> + * <li>{@link #atanh(double)}</li> + * </ul> + * The following methods are found in StrictMath since 1.6 only + * <ul> + * <li>{@link #copySign(double, double)}</li> + * <li>{@link #getExponent(double)}</li> + * <li>{@link #nextAfter(double,double)}</li> + * <li>{@link #nextUp(double)}</li> + * <li>{@link #scalb(double, int)}</li> + * <li>{@link #copySign(float, float)}</li> + * <li>{@link #getExponent(float)}</li> + * <li>{@link #nextAfter(float,double)}</li> + * <li>{@link #nextUp(float)}</li> + * <li>{@link #scalb(float, int)}</li> + * </ul> + * @version $Revision: 1074294 $ $Date: 2011-02-24 22:18:59 +0100 (jeu. 24 févr. 2011) $ + * @since 2.2 + */ +public class FastMath { + + /** Archimede's constant PI, ratio of circle circumference to diameter. */ + public static final double PI = 105414357.0 / 33554432.0 + 1.984187159361080883e-9; + + /** Napier's constant e, base of the natural logarithm. */ + public static final double E = 2850325.0 / 1048576.0 + 8.254840070411028747e-8; + + /** Exponential evaluated at integer values, + * exp(x) = expIntTableA[x + 750] + expIntTableB[x+750]. + */ + private static final double EXP_INT_TABLE_A[] = new double[1500]; + + /** Exponential evaluated at integer values, + * exp(x) = expIntTableA[x + 750] + expIntTableB[x+750] + */ + private static final double EXP_INT_TABLE_B[] = new double[1500]; + + /** 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_A[] = new double[1025]; + + /** 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[] = new double[1025]; + + /** Factorial table, for Taylor series expansions. */ + private static final double FACT[] = new double[20]; + + /** Extended precision logarithm table over the range 1 - 2 in increments of 2^-10. */ + private static final double LN_MANT[][] = new double[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 slowLog. */ + private static final double LN_SPLIT_COEF[][] = { + {2.0, 0.0}, + {0.6666666269302368, 3.9736429850260626E-8}, + {0.3999999761581421, 2.3841857910019882E-8}, + {0.2857142686843872, 1.7029898543501842E-8}, + {0.2222222089767456, 1.3245471311735498E-8}, + {0.1818181574344635, 2.4384203044354907E-8}, + {0.1538461446762085, 9.140260083262505E-9}, + {0.13333332538604736, 9.220590270857665E-9}, + {0.11764700710773468, 1.2393345855018391E-8}, + {0.10526403784751892, 8.251545029714408E-9}, + {0.0952233225107193, 1.2675934823758863E-8}, + {0.08713622391223907, 1.1430250008909141E-8}, + {0.07842259109020233, 2.404307984052299E-9}, + {0.08371849358081818, 1.176342548272881E-8}, + {0.030589580535888672, 1.2958646899018938E-9}, + {0.14982303977012634, 1.225743062930824E-8}, + }; + + /** 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} + }; + + /** Sine table (high bits). */ + private static final double SINE_TABLE_A[] = new double[14]; + + /** Sine table (low bits). */ + private static final double SINE_TABLE_B[] = new double[14]; + + /** Cosine table (high bits). */ + private static final double COSINE_TABLE_A[] = new double[14]; + + /** Cosine table (low bits). */ + private static final double COSINE_TABLE_B[] = new double[14]; + + /** Tangent table, used by atan() (high bits). */ + private static final double TANGENT_TABLE_A[] = new double[14]; + + /** Tangent table, used by atan() (low bits). */ + private static final double TANGENT_TABLE_B[] = new double[14]; + + /** Bits of 1/(2*pi), need for reducePayneHanek(). */ + private static final long RECIP_2PI[] = new long[] { + (0x28be60dbL << 32) | 0x9391054aL, + (0x7f09d5f4L << 32) | 0x7d4d3770L, + (0x36d8a566L << 32) | 0x4f10e410L, + (0x7f9458eaL << 32) | 0xf7aef158L, + (0x6dc91b8eL << 32) | 0x909374b8L, + (0x01924bbaL << 32) | 0x82746487L, + (0x3f877ac7L << 32) | 0x2c4a69cfL, + (0xba208d7dL << 32) | 0x4baed121L, + (0x3a671c09L << 32) | 0xad17df90L, + (0x4e64758eL << 32) | 0x60d4ce7dL, + (0x272117e2L << 32) | 0xef7e4a0eL, + (0xc7fe25ffL << 32) | 0xf7816603L, + (0xfbcbc462L << 32) | 0xd6829b47L, + (0xdb4d9fb3L << 32) | 0xc9f2c26dL, + (0xd3d18fd9L << 32) | 0xa797fa8bL, + (0x5d49eeb1L << 32) | 0xfaf97c5eL, + (0xcf41ce7dL << 32) | 0xe294a4baL, + 0x9afed7ecL << 32 }; + + /** Bits of pi/4, need for reducePayneHanek(). */ + private static final long PI_O_4_BITS[] = new long[] { + (0xc90fdaa2L << 32) | 0x2168c234L, + (0xc4c6628bL << 32) | 0x80dc1cd1L }; + + /** Eighths. + * This is used by sinQ, because its faster to do a table lookup than + * a multiply in this time-critical routine + */ + private static final double EIGHTHS[] = {0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625}; + + /** Table of 2^((n+2)/3) */ + private static final double CBRTTWO[] = { 0.6299605249474366, + 0.7937005259840998, + 1.0, + 1.2599210498948732, + 1.5874010519681994 }; + + /* + * 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 + + /** Mask used to clear low order 30 bits */ + private static final long MASK_30BITS = -1L - (HEX_40000000 -1); // 0xFFFFFFFFC0000000L; + + /** 2^52 - double numbers this large must be integral (no fraction) or NaN or Infinite */ + private static final double TWO_POWER_52 = 4503599627370496.0; + + // Initialize tables + static { + int i; + + // Generate an array of factorials + FACT[0] = 1.0; + for (i = 1; i < FACT.length; i++) { + FACT[i] = FACT[i-1] * i; + } + + double tmp[] = new double[2]; + double recip[] = new double[2]; + + // Populate expIntTable + for (i = 0; i < 750; i++) { + expint(i, tmp); + EXP_INT_TABLE_A[i+750] = tmp[0]; + EXP_INT_TABLE_B[i+750] = tmp[1]; + + if (i != 0) { + // Negative integer powers + splitReciprocal(tmp, recip); + EXP_INT_TABLE_A[750-i] = recip[0]; + EXP_INT_TABLE_B[750-i] = recip[1]; + } + } + + // Populate expFracTable + for (i = 0; i < EXP_FRAC_TABLE_A.length; i++) { + slowexp(i/1024.0, tmp); + EXP_FRAC_TABLE_A[i] = tmp[0]; + EXP_FRAC_TABLE_B[i] = tmp[1]; + } + + // Populate lnMant table + for (i = 0; i < LN_MANT.length; i++) { + double d = Double.longBitsToDouble( (((long) i) << 42) | 0x3ff0000000000000L ); + LN_MANT[i] = slowLog(d); + } + + // Build the sine and cosine tables + buildSinCosTables(); + } + + /** + * Private Constructor + */ + private FastMath() { + } + + // Generic helper methods + + /** + * Get the high order bits from the mantissa. + * Equivalent to adding and subtracting HEX_40000 but also works for very large numbers + * + * @param d the value to split + * @return the high order part of the mantissa + */ + private static double doubleHighPart(double d) { + if (d > -MathUtils.SAFE_MIN && d < MathUtils.SAFE_MIN){ + return d; // These are un-normalised - don't try to convert + } + long xl = Double.doubleToLongBits(d); + xl = xl & MASK_30BITS; // Drop low order bits + return Double.longBitsToDouble(xl); + } + + /** Compute the square root of a number. + * <p><b>Note:</b> this implementation currently delegates to {@link Math#sqrt} + * @param a number on which evaluation is done + * @return square root of a + */ + public static double sqrt(final double a) { + return Math.sqrt(a); + } + + /** Compute the hyperbolic cosine of a number. + * @param x number on which evaluation is done + * @return hyperbolic cosine of x + */ + public static double cosh(double x) { + if (x != x) { + return x; + } + + if (x > 20.0) { + return exp(x)/2.0; + } + + if (x < -20) { + return exp(-x)/2.0; + } + + 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 + */ + public static double sinh(double x) { + boolean negate = false; + if (x != x) { + return x; + } + + if (x > 20.0) { + return exp(x)/2.0; + } + + if (x < -20) { + return -exp(-x)/2.0; + } + + 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 + */ + public static double tanh(double x) { + boolean negate = false; + + if (x != x) { + return x; + } + + 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 inverse hyperbolic cosine of a number. + * @param a number on which evaluation is done + * @return inverse hyperbolic cosine of a + */ + public static double acosh(final double a) { + return FastMath.log(a + FastMath.sqrt(a * a - 1)); + } + + /** Compute the inverse hyperbolic sine of a number. + * @param a number on which evaluation is done + * @return inverse hyperbolic sine of a + */ + public static double asinh(double a) { + + boolean negative = false; + if (a < 0) { + negative = true; + a = -a; + } + + double absAsinh; + if (a > 0.167) { + absAsinh = FastMath.log(FastMath.sqrt(a * a + 1) + a); + } else { + final double a2 = a * a; + if (a > 0.097) { + absAsinh = a * (1 - a2 * (1 / 3.0 - a2 * (1 / 5.0 - a2 * (1 / 7.0 - a2 * (1 / 9.0 - a2 * (1.0 / 11.0 - a2 * (1.0 / 13.0 - a2 * (1.0 / 15.0 - a2 * (1.0 / 17.0) * 15.0 / 16.0) * 13.0 / 14.0) * 11.0 / 12.0) * 9.0 / 10.0) * 7.0 / 8.0) * 5.0 / 6.0) * 3.0 / 4.0) / 2.0); + } else if (a > 0.036) { + absAsinh = a * (1 - a2 * (1 / 3.0 - a2 * (1 / 5.0 - a2 * (1 / 7.0 - a2 * (1 / 9.0 - a2 * (1.0 / 11.0 - a2 * (1.0 / 13.0) * 11.0 / 12.0) * 9.0 / 10.0) * 7.0 / 8.0) * 5.0 / 6.0) * 3.0 / 4.0) / 2.0); + } else if (a > 0.0036) { + absAsinh = a * (1 - a2 * (1 / 3.0 - a2 * (1 / 5.0 - a2 * (1 / 7.0 - a2 * (1 / 9.0) * 7.0 / 8.0) * 5.0 / 6.0) * 3.0 / 4.0) / 2.0); + } else { + absAsinh = a * (1 - a2 * (1 / 3.0 - a2 * (1 / 5.0) * 3.0 / 4.0) / 2.0); + } + } + + return negative ? -absAsinh : absAsinh; + + } + + /** Compute the inverse hyperbolic tangent of a number. + * @param a number on which evaluation is done + * @return inverse hyperbolic tangent of a + */ + public static double atanh(double a) { + + boolean negative = false; + if (a < 0) { + negative = true; + a = -a; + } + + double absAtanh; + if (a > 0.15) { + absAtanh = 0.5 * FastMath.log((1 + a) / (1 - a)); + } else { + final double a2 = a * a; + if (a > 0.087) { + absAtanh = a * (1 + a2 * (1.0 / 3.0 + a2 * (1.0 / 5.0 + a2 * (1.0 / 7.0 + a2 * (1.0 / 9.0 + a2 * (1.0 / 11.0 + a2 * (1.0 / 13.0 + a2 * (1.0 / 15.0 + a2 * (1.0 / 17.0))))))))); + } else if (a > 0.031) { + absAtanh = a * (1 + a2 * (1.0 / 3.0 + a2 * (1.0 / 5.0 + a2 * (1.0 / 7.0 + a2 * (1.0 / 9.0 + a2 * (1.0 / 11.0 + a2 * (1.0 / 13.0))))))); + } else if (a > 0.003) { + absAtanh = a * (1 + a2 * (1.0 / 3.0 + a2 * (1.0 / 5.0 + a2 * (1.0 / 7.0 + a2 * (1.0 / 9.0))))); + } else { + absAtanh = a * (1 + a2 * (1.0 / 3.0 + a2 * (1.0 / 5.0))); + } + } + + return negative ? -absAtanh : absAtanh; + + } + + /** Compute the signum of a number. + * The signum is -1 for negative numbers, +1 for positive numbers and 0 otherwise + * @param a number on which evaluation is done + * @return -1.0, -0.0, +0.0, +1.0 or NaN depending on sign of a + */ + public static double signum(final double a) { + return (a < 0.0) ? -1.0 : ((a > 0.0) ? 1.0 : a); // return +0.0/-0.0/NaN depending on a + } + + /** Compute the signum of a number. + * The signum is -1 for negative numbers, +1 for positive numbers and 0 otherwise + * @param a number on which evaluation is done + * @return -1.0, -0.0, +0.0, +1.0 or NaN depending on sign of a + */ + public static float signum(final float a) { + return (a < 0.0f) ? -1.0f : ((a > 0.0f) ? 1.0f : a); // return +0.0/-0.0/NaN depending on a + } + + /** Compute next number towards positive infinity. + * @param a number to which neighbor should be computed + * @return neighbor of a towards positive infinity + */ + public static double nextUp(final double a) { + return nextAfter(a, Double.POSITIVE_INFINITY); + } + + /** Compute next number towards positive infinity. + * @param a number to which neighbor should be computed + * @return neighbor of a towards positive infinity + */ + public static float nextUp(final float a) { + return nextAfter(a, Float.POSITIVE_INFINITY); + } + + /** Returns a pseudo-random number between 0.0 and 1.0. + * <p><b>Note:</b> this implementation currently delegates to {@link Math#random} + * @return a random number between 0.0 and 1.0 + */ + public static double random() { + return Math.random(); + } + + /** + * 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 e<sup>x</sup> + */ + public 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 = EXP_INT_TABLE_A[750-intVal]; + intPartB = EXP_INT_TABLE_B[750-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 = EXP_INT_TABLE_A[750+intVal]; + intPartB = EXP_INT_TABLE_B[750+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 = EXP_FRAC_TABLE_A[intFrac]; + final double fracPartB = 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 percison. + */ + 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 contant 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 + */ + public 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 = EXP_FRAC_TABLE_A[intFrac] - 1.0; + double tempB = 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; + } + + /** + * For x between 0 and 1, returns exp(x), uses extended precision + * @param x argument of exponential + * @param result placeholder where to place exp(x) split in two terms + * for extra precision (i.e. exp(x) = result[0] ° result[1] + * @return exp(x) + */ + private static double slowexp(final double x, final double result[]) { + final double xs[] = new double[2]; + final double ys[] = new double[2]; + final double facts[] = new double[2]; + final double as[] = new double[2]; + split(x, xs); + ys[0] = ys[1] = 0.0; + + for (int i = 19; i >= 0; i--) { + splitMult(xs, ys, as); + ys[0] = as[0]; + ys[1] = as[1]; + + split(FACT[i], as); + splitReciprocal(as, facts); + + splitAdd(ys, facts, as); + ys[0] = as[0]; + ys[1] = as[1]; + } + + if (result != null) { + result[0] = ys[0]; + result[1] = ys[1]; + } + + return ys[0] + ys[1]; + } + + /** Compute split[0], split[1] such that their sum is equal to d, + * and split[0] has its 30 least significant bits as zero. + * @param d number to split + * @param split placeholder where to place the result + */ + private static void split(final double d, final double split[]) { + if (d < 8e298 && d > -8e298) { + final double a = d * HEX_40000000; + split[0] = (d + a) - a; + split[1] = d - split[0]; + } else { + final double a = d * 9.31322574615478515625E-10; + split[0] = (d + a - d) * HEX_40000000; + split[1] = d - split[0]; + } + } + + /** Recompute a split. + * @param a input/out array containing the split, changed + * on output + */ + private static void resplit(final double a[]) { + final double c = a[0] + a[1]; + final double d = -(c - a[0] - a[1]); + + if (c < 8e298 && c > -8e298) { + double z = c * HEX_40000000; + a[0] = (c + z) - z; + a[1] = c - a[0] + d; + } else { + double z = c * 9.31322574615478515625E-10; + a[0] = (c + z - c) * HEX_40000000; + a[1] = c - a[0] + d; + } + } + + /** Multiply two numbers in split form. + * @param a first term of multiplication + * @param b second term of multiplication + * @param ans placeholder where to put the result + */ + private static void splitMult(double a[], double b[], double ans[]) { + ans[0] = a[0] * b[0]; + ans[1] = a[0] * b[1] + a[1] * b[0] + a[1] * b[1]; + + /* Resplit */ + resplit(ans); + } + + /** Add two numbers in split form. + * @param a first term of addition + * @param b second term of addition + * @param ans placeholder where to put the result + */ + private static void splitAdd(final double a[], final double b[], final double ans[]) { + ans[0] = a[0] + b[0]; + ans[1] = a[1] + b[1]; + + resplit(ans); + } + + /** Compute the reciprocal of in. Use the following algorithm. + * in = c + d. + * want to find x + y such that x+y = 1/(c+d) and x is much + * larger than y and x has several zero bits on the right. + * + * Set b = 1/(2^22), a = 1 - b. Thus (a+b) = 1. + * Use following identity to compute (a+b)/(c+d) + * + * (a+b)/(c+d) = a/c + (bc - ad) / (c^2 + cd) + * set x = a/c and y = (bc - ad) / (c^2 + cd) + * This will be close to the right answer, but there will be + * some rounding in the calculation of X. So by carefully + * computing 1 - (c+d)(x+y) we can compute an error and + * add that back in. This is done carefully so that terms + * of similar size are subtracted first. + * @param in initial number, in split form + * @param result placeholder where to put the result + */ + private static void splitReciprocal(final double in[], final double result[]) { + final double b = 1.0/4194304.0; + final double a = 1.0 - b; + + if (in[0] == 0.0) { + in[0] = in[1]; + in[1] = 0.0; + } + + result[0] = a / in[0]; + result[1] = (b*in[0]-a*in[1]) / (in[0]*in[0] + in[0]*in[1]); + + if (result[1] != result[1]) { // can happen if result[1] is NAN + result[1] = 0.0; + } + + /* Resplit */ + resplit(result); + + for (int i = 0; i < 2; i++) { + /* this may be overkill, probably once is enough */ + double err = 1.0 - result[0] * in[0] - result[0] * in[1] - + result[1] * in[0] - result[1] * in[1]; + /*err = 1.0 - err; */ + err = err * (result[0] + result[1]); + /*printf("err = %16e\n", err); */ + result[1] += err; + } + } + + /** Compute (a[0] + a[1]) * (b[0] + b[1]) in extended precision. + * @param a first term of the multiplication + * @param b second term of the multiplication + * @param result placeholder where to put the result + */ + private static void quadMult(final double a[], final double b[], final double result[]) { + final double xs[] = new double[2]; + final double ys[] = new double[2]; + final double zs[] = new double[2]; + + /* a[0] * b[0] */ + split(a[0], xs); + split(b[0], ys); + splitMult(xs, ys, zs); + + result[0] = zs[0]; + result[1] = zs[1]; + + /* a[0] * b[1] */ + split(b[1], ys); + splitMult(xs, ys, zs); + + double tmp = result[0] + zs[0]; + result[1] = result[1] - (tmp - result[0] - zs[0]); + result[0] = tmp; + tmp = result[0] + zs[1]; + result[1] = result[1] - (tmp - result[0] - zs[1]); + result[0] = tmp; + + /* a[1] * b[0] */ + split(a[1], xs); + split(b[0], ys); + splitMult(xs, ys, zs); + + tmp = result[0] + zs[0]; + result[1] = result[1] - (tmp - result[0] - zs[0]); + result[0] = tmp; + tmp = result[0] + zs[1]; + result[1] = result[1] - (tmp - result[0] - zs[1]); + result[0] = tmp; + + /* a[1] * b[0] */ + split(a[1], xs); + split(b[1], ys); + splitMult(xs, ys, zs); + + tmp = result[0] + zs[0]; + result[1] = result[1] - (tmp - result[0] - zs[0]); + result[0] = tmp; + tmp = result[0] + zs[1]; + result[1] = result[1] - (tmp - result[0] - zs[1]); + result[0] = tmp; + } + + /** Compute exp(p) for a integer p in extended precision. + * @param p integer whose exponential is requested + * @param result placeholder where to put the result in extended precision + * @return exp(p) in standard precision (equal to result[0] + result[1]) + */ + private static double expint(int p, final double result[]) { + //double x = M_E; + final double xs[] = new double[2]; + final double as[] = new double[2]; + final double ys[] = new double[2]; + //split(x, xs); + //xs[1] = (double)(2.7182818284590452353602874713526625L - xs[0]); + //xs[0] = 2.71827697753906250000; + //xs[1] = 4.85091998273542816811e-06; + //xs[0] = Double.longBitsToDouble(0x4005bf0800000000L); + //xs[1] = Double.longBitsToDouble(0x3ed458a2bb4a9b00L); + + /* E */ + xs[0] = 2.718281828459045; + xs[1] = 1.4456468917292502E-16; + + split(1.0, ys); + + while (p > 0) { + if ((p & 1) != 0) { + quadMult(ys, xs, as); + ys[0] = as[0]; ys[1] = as[1]; + } + + quadMult(xs, xs, as); + xs[0] = as[0]; xs[1] = as[1]; + + p >>= 1; + } + + if (result != null) { + result[0] = ys[0]; + result[1] = ys[1]; + + resplit(result); + } + + return ys[0] + ys[1]; + } + + + /** + * Natural logarithm. + * + * @param x a double + * @return log(x) + */ + public static double log(final double x) { + return log(x, null); + } + + /** + * 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.doubleToLongBits(x); + + /* Handle special cases of negative input, and NaN */ + if ((bits & 0x8000000000000000L) != 0 || x != x) { + if (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) { + if (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; + + double ya = LN_QUICK_COEF[LN_QUICK_COEF.length-1][0]; + double yb = LN_QUICK_COEF[LN_QUICK_COEF.length-1][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 */ + aa = ya + LN_QUICK_COEF[i][0]; + ab = yb + LN_QUICK_COEF[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) + double lnm[] = 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; + 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. */ + double numer = bits & 0x3ffffffffffL; + double denom = TWO_POWER_52 + (bits & 0x000ffc0000000000L); + aa = numer - xa*denom - xb * denom; + xb += aa / denom; + + /* Remez polynomial evaluation */ + double ya = LN_HI_PREC_COEF[LN_HI_PREC_COEF.length-1][0]; + double yb = LN_HI_PREC_COEF[LN_HI_PREC_COEF.length-1][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 */ + aa = ya + LN_HI_PREC_COEF[i][0]; + ab = yb + LN_HI_PREC_COEF[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; + } + + /** Compute log(1 + x). + * @param x a number + * @return log(1 + x) + */ + public static double log1p(final double x) { + double xpa = 1.0 + x; + double xpb = -(xpa - 1.0 - x); + + if (x == -1) { + return x/0.0; // -Infinity + } + + if (x > 0 && 1/x == 0) { // x = Infinity + return x; + } + + if (x>1e-6 || x<-1e-6) { + double hiPrec[] = new double[2]; + + final double lores = log(xpa, hiPrec); + if (Double.isInfinite(lores)){ // don't allow this to be converted to NaN + return lores; + } + + /* Do a taylor series expansion around xpa */ + /* f(x+y) = f(x) + f'(x)*y + f''(x)/2 y^2 */ + double fx1 = xpb/xpa; + + double epsilon = 0.5 * fx1 + 1.0; + epsilon = epsilon * fx1; + + return epsilon + hiPrec[1] + hiPrec[0]; + } + + /* Value is small |x| < 1e6, do a Taylor series centered on 1.0 */ + double y = x * 0.333333333333333 - 0.5; + y = y * x + 1.0; + y = y * x; + + return y; + } + + /** Compute the base 10 logarithm. + * @param x a number + * @return log10(x) + */ + public static double log10(final double x) { + final double hiPrec[] = new double[2]; + + final double lores = log(x, hiPrec); + if (Double.isInfinite(lores)){ // don't allow this to be converted to NaN + return lores; + } + + final double tmp = hiPrec[0] * HEX_40000000; + final double lna = hiPrec[0] + tmp - tmp; + final double lnb = hiPrec[0] - lna + hiPrec[1]; + + final double rln10a = 0.4342944622039795; + final double rln10b = 1.9699272335463627E-8; + + return rln10b * lnb + rln10b * lna + rln10a * lnb + rln10a * lna; + } + + /** + * Power function. Compute x^y. + * + * @param x a double + * @param y a double + * @return double + */ + public 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.doubleToLongBits(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 && 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_52 || y <= -TWO_POWER_52) { + 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; + } + + /** xi in the range of [1, 2]. + * 3 5 7 + * x+1 / x x x \ + * ln ----- = 2 * | x + ---- + ---- + ---- + ... | + * 1-x \ 3 5 7 / + * + * So, compute a Remez approximation of the following function + * + * ln ((sqrt(x)+1)/(1-sqrt(x))) / x + * + * This will be an even function with only positive coefficents. + * x is in the range [0 - 1/3]. + * + * Transform xi for input to the above function by setting + * x = (xi-1)/(xi+1). Input to the polynomial is x^2, then + * the result is multiplied by x. + * @param xi number from which log is requested + * @return log(xi) + */ + private static double[] slowLog(double xi) { + double x[] = new double[2]; + double x2[] = new double[2]; + double y[] = new double[2]; + double a[] = new double[2]; + + split(xi, x); + + /* Set X = (x-1)/(x+1) */ + x[0] += 1.0; + resplit(x); + splitReciprocal(x, a); + x[0] -= 2.0; + resplit(x); + splitMult(x, a, y); + x[0] = y[0]; + x[1] = y[1]; + + /* Square X -> X2*/ + splitMult(x, x, x2); + + + //x[0] -= 1.0; + //resplit(x); + + y[0] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][0]; + y[1] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][1]; + + for (int i = LN_SPLIT_COEF.length-2; i >= 0; i--) { + splitMult(y, x2, a); + y[0] = a[0]; + y[1] = a[1]; + splitAdd(y, LN_SPLIT_COEF[i], a); + y[0] = a[0]; + y[1] = a[1]; + } + + splitMult(y, x, a); + y[0] = a[0]; + y[1] = a[1]; + + return y; + } + + /** + * For x between 0 and pi/4 compute sine. + * @param x number from which sine is requested + * @param result placeholder where to put the result in extended precision + * @return sin(x) + */ + private static double slowSin(final double x, final double result[]) { + final double xs[] = new double[2]; + final double ys[] = new double[2]; + final double facts[] = new double[2]; + final double as[] = new double[2]; + split(x, xs); + ys[0] = ys[1] = 0.0; + + for (int i = 19; i >= 0; i--) { + splitMult(xs, ys, as); + ys[0] = as[0]; ys[1] = as[1]; + + if ( (i & 1) == 0) { + continue; + } + + split(FACT[i], as); + splitReciprocal(as, facts); + + if ( (i & 2) != 0 ) { + facts[0] = -facts[0]; + facts[1] = -facts[1]; + } + + splitAdd(ys, facts, as); + ys[0] = as[0]; ys[1] = as[1]; + } + + if (result != null) { + result[0] = ys[0]; + result[1] = ys[1]; + } + + return ys[0] + ys[1]; + } + + /** + * For x between 0 and pi/4 compute cosine + * @param x number from which cosine is requested + * @param result placeholder where to put the result in extended precision + * @return cos(x) + */ + private static double slowCos(final double x, final double result[]) { + + final double xs[] = new double[2]; + final double ys[] = new double[2]; + final double facts[] = new double[2]; + final double as[] = new double[2]; + split(x, xs); + ys[0] = ys[1] = 0.0; + + for (int i = 19; i >= 0; i--) { + splitMult(xs, ys, as); + ys[0] = as[0]; ys[1] = as[1]; + + if ( (i & 1) != 0) { + continue; + } + + split(FACT[i], as); + splitReciprocal(as, facts); + + if ( (i & 2) != 0 ) { + facts[0] = -facts[0]; + facts[1] = -facts[1]; + } + + splitAdd(ys, facts, as); + ys[0] = as[0]; ys[1] = as[1]; + } + + if (result != null) { + result[0] = ys[0]; + result[1] = ys[1]; + } + + return ys[0] + ys[1]; + } + + /** Build the sine and cosine tables. + */ + private static void buildSinCosTables() { + final double result[] = new double[2]; + + /* Use taylor series for 0 <= x <= 6/8 */ + for (int i = 0; i < 7; i++) { + double x = i / 8.0; + + slowSin(x, result); + SINE_TABLE_A[i] = result[0]; + SINE_TABLE_B[i] = result[1]; + + slowCos(x, result); + COSINE_TABLE_A[i] = result[0]; + COSINE_TABLE_B[i] = result[1]; + } + + /* Use angle addition formula to complete table to 13/8, just beyond pi/2 */ + for (int i = 7; i < 14; i++) { + double xs[] = new double[2]; + double ys[] = new double[2]; + double as[] = new double[2]; + double bs[] = new double[2]; + double temps[] = new double[2]; + + if ( (i & 1) == 0) { + // Even, use double angle + xs[0] = SINE_TABLE_A[i/2]; + xs[1] = SINE_TABLE_B[i/2]; + ys[0] = COSINE_TABLE_A[i/2]; + ys[1] = COSINE_TABLE_B[i/2]; + + /* compute sine */ + splitMult(xs, ys, result); + SINE_TABLE_A[i] = result[0] * 2.0; + SINE_TABLE_B[i] = result[1] * 2.0; + + /* Compute cosine */ + splitMult(ys, ys, as); + splitMult(xs, xs, temps); + temps[0] = -temps[0]; + temps[1] = -temps[1]; + splitAdd(as, temps, result); + COSINE_TABLE_A[i] = result[0]; + COSINE_TABLE_B[i] = result[1]; + } else { + xs[0] = SINE_TABLE_A[i/2]; + xs[1] = SINE_TABLE_B[i/2]; + ys[0] = COSINE_TABLE_A[i/2]; + ys[1] = COSINE_TABLE_B[i/2]; + as[0] = SINE_TABLE_A[i/2+1]; + as[1] = SINE_TABLE_B[i/2+1]; + bs[0] = COSINE_TABLE_A[i/2+1]; + bs[1] = COSINE_TABLE_B[i/2+1]; + + /* compute sine */ + splitMult(xs, bs, temps); + splitMult(ys, as, result); + splitAdd(result, temps, result); + SINE_TABLE_A[i] = result[0]; + SINE_TABLE_B[i] = result[1]; + + /* Compute cosine */ + splitMult(ys, bs, result); + splitMult(xs, as, temps); + temps[0] = -temps[0]; + temps[1] = -temps[1]; + splitAdd(result, temps, result); + COSINE_TABLE_A[i] = result[0]; + COSINE_TABLE_B[i] = result[1]; + } + } + + /* Compute tangent = sine/cosine */ + for (int i = 0; i < 14; i++) { + double xs[] = new double[2]; + double ys[] = new double[2]; + double as[] = new double[2]; + + as[0] = COSINE_TABLE_A[i]; + as[1] = COSINE_TABLE_B[i]; + + splitReciprocal(as, ys); + + xs[0] = SINE_TABLE_A[i]; + xs[1] = SINE_TABLE_B[i]; + + splitMult(xs, ys, as); + + TANGENT_TABLE_A[i] = as[0]; + TANGENT_TABLE_B[i] = as[1]; + } + + } + + /** + * Computes sin(x) - x, where |x| < 1/16. + * Use a Remez polynomial approximation. + * @param x a number smaller than 1/16 + * @return sin(x) - x + */ + private static double polySine(final double x) + { + double x2 = x*x; + + double p = 2.7553817452272217E-6; + p = p * x2 + -1.9841269659586505E-4; + p = p * x2 + 0.008333333333329196; + p = p * x2 + -0.16666666666666666; + //p *= x2; + //p *= x; + p = p * x2 * x; + + return p; + } + + /** + * Computes cos(x) - 1, where |x| < 1/16. + * Use a Remez polynomial approximation. + * @param x a number smaller than 1/16 + * @return cos(x) - 1 + */ + private static double polyCosine(double x) { + double x2 = x*x; + + double p = 2.479773539153719E-5; + p = p * x2 + -0.0013888888689039883; + p = p * x2 + 0.041666666666621166; + p = p * x2 + -0.49999999999999994; + p *= x2; + + return p; + } + + /** + * Compute sine over the first quadrant (0 < x < pi/2). + * Use combination of table lookup and rational polynomial expansion. + * @param xa number from which sine is requested + * @param xb extra bits for x (may be 0.0) + * @return sin(xa + xb) + */ + private static double sinQ(double xa, double xb) { + int idx = (int) ((xa * 8.0) + 0.5); + final double epsilon = xa - EIGHTHS[idx]; //idx*0.125; + + // Table lookups + final double sintA = SINE_TABLE_A[idx]; + final double sintB = SINE_TABLE_B[idx]; + final double costA = COSINE_TABLE_A[idx]; + final double costB = COSINE_TABLE_B[idx]; + + // Polynomial eval of sin(epsilon), cos(epsilon) + double sinEpsA = epsilon; + double sinEpsB = polySine(epsilon); + final double cosEpsA = 1.0; + final double cosEpsB = polyCosine(epsilon); + + // Split epsilon xa + xb = x + final double temp = sinEpsA * HEX_40000000; + double temp2 = (sinEpsA + temp) - temp; + sinEpsB += sinEpsA - temp2; + sinEpsA = temp2; + + /* Compute sin(x) by angle addition formula */ + double result; + + /* Compute the following sum: + * + * result = sintA + costA*sinEpsA + sintA*cosEpsB + costA*sinEpsB + + * sintB + costB*sinEpsA + sintB*cosEpsB + costB*sinEpsB; + * + * Ranges of elements + * + * xxxtA 0 PI/2 + * xxxtB -1.5e-9 1.5e-9 + * sinEpsA -0.0625 0.0625 + * sinEpsB -6e-11 6e-11 + * cosEpsA 1.0 + * cosEpsB 0 -0.0625 + * + */ + + //result = sintA + costA*sinEpsA + sintA*cosEpsB + costA*sinEpsB + + // sintB + costB*sinEpsA + sintB*cosEpsB + costB*sinEpsB; + + //result = sintA + sintA*cosEpsB + sintB + sintB * cosEpsB; + //result += costA*sinEpsA + costA*sinEpsB + costB*sinEpsA + costB * sinEpsB; + double a = 0; + double b = 0; + + double t = sintA; + double c = a + t; + double d = -(c - a - t); + a = c; + b = b + d; + + t = costA * sinEpsA; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + b = b + sintA * cosEpsB + costA * sinEpsB; + /* + t = sintA*cosEpsB; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + t = costA*sinEpsB; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + */ + + b = b + sintB + costB * sinEpsA + sintB * cosEpsB + costB * sinEpsB; + /* + t = sintB; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + t = costB*sinEpsA; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + t = sintB*cosEpsB; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + t = costB*sinEpsB; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + */ + + if (xb != 0.0) { + t = ((costA + costB) * (cosEpsA + cosEpsB) - + (sintA + sintB) * (sinEpsA + sinEpsB)) * xb; // approximate cosine*xb + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + } + + result = a + b; + + return result; + } + + /** + * Compute cosine in the first quadrant by subtracting input from PI/2 and + * then calling sinQ. This is more accurate as the input approaches PI/2. + * @param xa number from which cosine is requested + * @param xb extra bits for x (may be 0.0) + * @return cos(xa + xb) + */ + private static double cosQ(double xa, double xb) { + final double pi2a = 1.5707963267948966; + final double pi2b = 6.123233995736766E-17; + + final double a = pi2a - xa; + double b = -(a - pi2a + xa); + b += pi2b - xb; + + return sinQ(a, b); + } + + /** + * Compute tangent (or cotangent) over the first quadrant. 0 < x < pi/2 + * Use combination of table lookup and rational polynomial expansion. + * @param xa number from which sine is requested + * @param xb extra bits for x (may be 0.0) + * @param cotanFlag if true, compute the cotangent instead of the tangent + * @return tan(xa+xb) (or cotangent, depending on cotanFlag) + */ + private static double tanQ(double xa, double xb, boolean cotanFlag) { + + int idx = (int) ((xa * 8.0) + 0.5); + final double epsilon = xa - EIGHTHS[idx]; //idx*0.125; + + // Table lookups + final double sintA = SINE_TABLE_A[idx]; + final double sintB = SINE_TABLE_B[idx]; + final double costA = COSINE_TABLE_A[idx]; + final double costB = COSINE_TABLE_B[idx]; + + // Polynomial eval of sin(epsilon), cos(epsilon) + double sinEpsA = epsilon; + double sinEpsB = polySine(epsilon); + final double cosEpsA = 1.0; + final double cosEpsB = polyCosine(epsilon); + + // Split epsilon xa + xb = x + double temp = sinEpsA * HEX_40000000; + double temp2 = (sinEpsA + temp) - temp; + sinEpsB += sinEpsA - temp2; + sinEpsA = temp2; + + /* Compute sin(x) by angle addition formula */ + + /* Compute the following sum: + * + * result = sintA + costA*sinEpsA + sintA*cosEpsB + costA*sinEpsB + + * sintB + costB*sinEpsA + sintB*cosEpsB + costB*sinEpsB; + * + * Ranges of elements + * + * xxxtA 0 PI/2 + * xxxtB -1.5e-9 1.5e-9 + * sinEpsA -0.0625 0.0625 + * sinEpsB -6e-11 6e-11 + * cosEpsA 1.0 + * cosEpsB 0 -0.0625 + * + */ + + //result = sintA + costA*sinEpsA + sintA*cosEpsB + costA*sinEpsB + + // sintB + costB*sinEpsA + sintB*cosEpsB + costB*sinEpsB; + + //result = sintA + sintA*cosEpsB + sintB + sintB * cosEpsB; + //result += costA*sinEpsA + costA*sinEpsB + costB*sinEpsA + costB * sinEpsB; + double a = 0; + double b = 0; + + // Compute sine + double t = sintA; + double c = a + t; + double d = -(c - a - t); + a = c; + b = b + d; + + t = costA*sinEpsA; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + b = b + sintA*cosEpsB + costA*sinEpsB; + b = b + sintB + costB*sinEpsA + sintB*cosEpsB + costB*sinEpsB; + + double sina = a + b; + double sinb = -(sina - a - b); + + // Compute cosine + + a = b = c = d = 0.0; + + t = costA*cosEpsA; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + t = -sintA*sinEpsA; + c = a + t; + d = -(c - a - t); + a = c; + b = b + d; + + b = b + costB*cosEpsA + costA*cosEpsB + costB*cosEpsB; + b = b - (sintB*sinEpsA + sintA*sinEpsB + sintB*sinEpsB); + + double cosa = a + b; + double cosb = -(cosa - a - b); + + if (cotanFlag) { + double tmp; + tmp = cosa; cosa = sina; sina = tmp; + tmp = cosb; cosb = sinb; sinb = tmp; + } + + + /* estimate and correct, compute 1.0/(cosa+cosb) */ + /* + double est = (sina+sinb)/(cosa+cosb); + double err = (sina - cosa*est) + (sinb - cosb*est); + est += err/(cosa+cosb); + err = (sina - cosa*est) + (sinb - cosb*est); + */ + + // f(x) = 1/x, f'(x) = -1/x^2 + + double est = sina/cosa; + + /* Split the estimate to get more accurate read on division rounding */ + temp = est * HEX_40000000; + double esta = (est + temp) - temp; + double estb = est - esta; + + temp = cosa * HEX_40000000; + double cosaa = (cosa + temp) - temp; + double cosab = cosa - cosaa; + + //double err = (sina - est*cosa)/cosa; // Correction for division rounding + double err = (sina - esta*cosaa - esta*cosab - estb*cosaa - estb*cosab)/cosa; // Correction for division rounding + err += sinb/cosa; // Change in est due to sinb + err += -sina * cosb / cosa / cosa; // Change in est due to cosb + + if (xb != 0.0) { + // tan' = 1 + tan^2 cot' = -(1 + cot^2) + // Approximate impact of xb + double xbadj = xb + est*est*xb; + if (cotanFlag) { + xbadj = -xbadj; + } + + err += xbadj; + } + + return est+err; + } + + /** Reduce the input argument using the Payne and Hanek method. + * This is good for all inputs 0.0 < x < inf + * Output is remainder after dividing by PI/2 + * The result array should contain 3 numbers. + * result[0] is the integer portion, so mod 4 this gives the quadrant. + * result[1] is the upper bits of the remainder + * result[2] is the lower bits of the remainder + * + * @param x number to reduce + * @param result placeholder where to put the result + */ + private static void reducePayneHanek(double x, double result[]) + { + /* Convert input double to bits */ + long inbits = Double.doubleToLongBits(x); + int exponent = (int) ((inbits >> 52) & 0x7ff) - 1023; + + /* Convert to fixed point representation */ + inbits &= 0x000fffffffffffffL; + inbits |= 0x0010000000000000L; + + /* Normalize input to be between 0.5 and 1.0 */ + exponent++; + inbits <<= 11; + + /* Based on the exponent, get a shifted copy of recip2pi */ + long shpi0; + long shpiA; + long shpiB; + int idx = exponent >> 6; + int shift = exponent - (idx << 6); + + if (shift != 0) { + shpi0 = (idx == 0) ? 0 : (RECIP_2PI[idx-1] << shift); + shpi0 |= RECIP_2PI[idx] >>> (64-shift); + shpiA = (RECIP_2PI[idx] << shift) | (RECIP_2PI[idx+1] >>> (64-shift)); + shpiB = (RECIP_2PI[idx+1] << shift) | (RECIP_2PI[idx+2] >>> (64-shift)); + } else { + shpi0 = (idx == 0) ? 0 : RECIP_2PI[idx-1]; + shpiA = RECIP_2PI[idx]; + shpiB = RECIP_2PI[idx+1]; + } + + /* Multiply input by shpiA */ + long a = inbits >>> 32; + long b = inbits & 0xffffffffL; + + long c = shpiA >>> 32; + long d = shpiA & 0xffffffffL; + + long ac = a * c; + long bd = b * d; + long bc = b * c; + long ad = a * d; + + long prodB = bd + (ad << 32); + long prodA = ac + (ad >>> 32); + + boolean bita = (bd & 0x8000000000000000L) != 0; + boolean bitb = (ad & 0x80000000L ) != 0; + boolean bitsum = (prodB & 0x8000000000000000L) != 0; + + /* Carry */ + if ( (bita && bitb) || + ((bita || bitb) && !bitsum) ) { + prodA++; + } + + bita = (prodB & 0x8000000000000000L) != 0; + bitb = (bc & 0x80000000L ) != 0; + + prodB = prodB + (bc << 32); + prodA = prodA + (bc >>> 32); + + bitsum = (prodB & 0x8000000000000000L) != 0; + + /* Carry */ + if ( (bita && bitb) || + ((bita || bitb) && !bitsum) ) { + prodA++; + } + + /* Multiply input by shpiB */ + c = shpiB >>> 32; + d = shpiB & 0xffffffffL; + ac = a * c; + bc = b * c; + ad = a * d; + + /* Collect terms */ + ac = ac + ((bc + ad) >>> 32); + + bita = (prodB & 0x8000000000000000L) != 0; + bitb = (ac & 0x8000000000000000L ) != 0; + prodB += ac; + bitsum = (prodB & 0x8000000000000000L) != 0; + /* Carry */ + if ( (bita && bitb) || + ((bita || bitb) && !bitsum) ) { + prodA++; + } + + /* Multiply by shpi0 */ + c = shpi0 >>> 32; + d = shpi0 & 0xffffffffL; + + bd = b * d; + bc = b * c; + ad = a * d; + + prodA += bd + ((bc + ad) << 32); + + /* + * prodA, prodB now contain the remainder as a fraction of PI. We want this as a fraction of + * PI/2, so use the following steps: + * 1.) multiply by 4. + * 2.) do a fixed point muliply by PI/4. + * 3.) Convert to floating point. + * 4.) Multiply by 2 + */ + + /* This identifies the quadrant */ + int intPart = (int)(prodA >>> 62); + + /* Multiply by 4 */ + prodA <<= 2; + prodA |= prodB >>> 62; + prodB <<= 2; + + /* Multiply by PI/4 */ + a = prodA >>> 32; + b = prodA & 0xffffffffL; + + c = PI_O_4_BITS[0] >>> 32; + d = PI_O_4_BITS[0] & 0xffffffffL; + + ac = a * c; + bd = b * d; + bc = b * c; + ad = a * d; + + long prod2B = bd + (ad << 32); + long prod2A = ac + (ad >>> 32); + + bita = (bd & 0x8000000000000000L) != 0; + bitb = (ad & 0x80000000L ) != 0; + bitsum = (prod2B & 0x8000000000000000L) != 0; + + /* Carry */ + if ( (bita && bitb) || + ((bita || bitb) && !bitsum) ) { + prod2A++; + } + + bita = (prod2B & 0x8000000000000000L) != 0; + bitb = (bc & 0x80000000L ) != 0; + + prod2B = prod2B + (bc << 32); + prod2A = prod2A + (bc >>> 32); + + bitsum = (prod2B & 0x8000000000000000L) != 0; + + /* Carry */ + if ( (bita && bitb) || + ((bita || bitb) && !bitsum) ) { + prod2A++; + } + + /* Multiply input by pio4bits[1] */ + c = PI_O_4_BITS[1] >>> 32; + d = PI_O_4_BITS[1] & 0xffffffffL; + ac = a * c; + bc = b * c; + ad = a * d; + + /* Collect terms */ + ac = ac + ((bc + ad) >>> 32); + + bita = (prod2B & 0x8000000000000000L) != 0; + bitb = (ac & 0x8000000000000000L ) != 0; + prod2B += ac; + bitsum = (prod2B & 0x8000000000000000L) != 0; + /* Carry */ + if ( (bita && bitb) || + ((bita || bitb) && !bitsum) ) { + prod2A++; + } + + /* Multiply inputB by pio4bits[0] */ + a = prodB >>> 32; + b = prodB & 0xffffffffL; + c = PI_O_4_BITS[0] >>> 32; + d = PI_O_4_BITS[0] & 0xffffffffL; + ac = a * c; + bc = b * c; + ad = a * d; + + /* Collect terms */ + ac = ac + ((bc + ad) >>> 32); + + bita = (prod2B & 0x8000000000000000L) != 0; + bitb = (ac & 0x8000000000000000L ) != 0; + prod2B += ac; + bitsum = (prod2B & 0x8000000000000000L) != 0; + /* Carry */ + if ( (bita && bitb) || + ((bita || bitb) && !bitsum) ) { + prod2A++; + } + + /* Convert to double */ + double tmpA = (prod2A >>> 12) / TWO_POWER_52; // High order 52 bits + double tmpB = (((prod2A & 0xfffL) << 40) + (prod2B >>> 24)) / TWO_POWER_52 / TWO_POWER_52; // Low bits + + double sumA = tmpA + tmpB; + double sumB = -(sumA - tmpA - tmpB); + + /* Multiply by PI/2 and return */ + result[0] = intPart; + result[1] = sumA * 2.0; + result[2] = sumB * 2.0; + } + + /** + * Sine function. + * @param x a number + * @return sin(x) + */ + public static double sin(double x) { + boolean negative = false; + int quadrant = 0; + double xa; + double xb = 0.0; + + /* Take absolute value of the input */ + xa = x; + if (x < 0) { + negative = true; + xa = -xa; + } + + /* Check for zero and negative zero */ + if (xa == 0.0) { + long bits = Double.doubleToLongBits(x); + if (bits < 0) { + return -0.0; + } + return 0.0; + } + + if (xa != xa || xa == Double.POSITIVE_INFINITY) { + return Double.NaN; + } + + /* Perform any argument reduction */ + if (xa > 3294198.0) { + // PI * (2**20) + // Argument too big for CodyWaite reduction. Must use + // PayneHanek. + double reduceResults[] = new double[3]; + reducePayneHanek(xa, reduceResults); + quadrant = ((int) reduceResults[0]) & 3; + xa = reduceResults[1]; + xb = reduceResults[2]; + } else if (xa > 1.5707963267948966) { + /* Inline the Cody/Waite reduction for performance */ + + // Estimate k + //k = (int)(xa / 1.5707963267948966); + int k = (int)(xa * 0.6366197723675814); + + // Compute remainder + double remA; + double remB; + while (true) { + double a = -k * 1.570796251296997; + remA = xa + a; + remB = -(remA - xa - a); + + a = -k * 7.549789948768648E-8; + double b = remA; + remA = a + b; + remB += -(remA - b - a); + + a = -k * 6.123233995736766E-17; + b = remA; + remA = a + b; + remB += -(remA - b - a); + + if (remA > 0.0) + break; + + // Remainder is negative, so decrement k and try again. + // This should only happen if the input is very close + // to an even multiple of pi/2 + k--; + } + quadrant = k & 3; + xa = remA; + xb = remB; + } + + if (negative) { + quadrant ^= 2; // Flip bit 1 + } + + switch (quadrant) { + case 0: + return sinQ(xa, xb); + case 1: + return cosQ(xa, xb); + case 2: + return -sinQ(xa, xb); + case 3: + return -cosQ(xa, xb); + default: + return Double.NaN; + } + } + + /** + * Cosine function + * @param x a number + * @return cos(x) + */ + public static double cos(double x) { + int quadrant = 0; + + /* Take absolute value of the input */ + double xa = x; + if (x < 0) { + xa = -xa; + } + + if (xa != xa || xa == Double.POSITIVE_INFINITY) { + return Double.NaN; + } + + /* Perform any argument reduction */ + double xb = 0; + if (xa > 3294198.0) { + // PI * (2**20) + // Argument too big for CodyWaite reduction. Must use + // PayneHanek. + double reduceResults[] = new double[3]; + reducePayneHanek(xa, reduceResults); + quadrant = ((int) reduceResults[0]) & 3; + xa = reduceResults[1]; + xb = reduceResults[2]; + } else if (xa > 1.5707963267948966) { + /* Inline the Cody/Waite reduction for performance */ + + // Estimate k + //k = (int)(xa / 1.5707963267948966); + int k = (int)(xa * 0.6366197723675814); + + // Compute remainder + double remA; + double remB; + while (true) { + double a = -k * 1.570796251296997; + remA = xa + a; + remB = -(remA - xa - a); + + a = -k * 7.549789948768648E-8; + double b = remA; + remA = a + b; + remB += -(remA - b - a); + + a = -k * 6.123233995736766E-17; + b = remA; + remA = a + b; + remB += -(remA - b - a); + + if (remA > 0.0) + break; + + // Remainder is negative, so decrement k and try again. + // This should only happen if the input is very close + // to an even multiple of pi/2 + k--; + } + quadrant = k & 3; + xa = remA; + xb = remB; + } + + //if (negative) + // quadrant = (quadrant + 2) % 4; + + switch (quadrant) { + case 0: + return cosQ(xa, xb); + case 1: + return -sinQ(xa, xb); + case 2: + return -cosQ(xa, xb); + case 3: + return sinQ(xa, xb); + default: + return Double.NaN; + } + } + + /** + * Tangent function + * @param x a number + * @return tan(x) + */ + public static double tan(double x) { + boolean negative = false; + int quadrant = 0; + + /* Take absolute value of the input */ + double xa = x; + if (x < 0) { + negative = true; + xa = -xa; + } + + /* Check for zero and negative zero */ + if (xa == 0.0) { + long bits = Double.doubleToLongBits(x); + if (bits < 0) { + return -0.0; + } + return 0.0; + } + + if (xa != xa || xa == Double.POSITIVE_INFINITY) { + return Double.NaN; + } + + /* Perform any argument reduction */ + double xb = 0; + if (xa > 3294198.0) { + // PI * (2**20) + // Argument too big for CodyWaite reduction. Must use + // PayneHanek. + double reduceResults[] = new double[3]; + reducePayneHanek(xa, reduceResults); + quadrant = ((int) reduceResults[0]) & 3; + xa = reduceResults[1]; + xb = reduceResults[2]; + } else if (xa > 1.5707963267948966) { + /* Inline the Cody/Waite reduction for performance */ + + // Estimate k + //k = (int)(xa / 1.5707963267948966); + int k = (int)(xa * 0.6366197723675814); + + // Compute remainder + double remA; + double remB; + while (true) { + double a = -k * 1.570796251296997; + remA = xa + a; + remB = -(remA - xa - a); + + a = -k * 7.549789948768648E-8; + double b = remA; + remA = a + b; + remB += -(remA - b - a); + + a = -k * 6.123233995736766E-17; + b = remA; + remA = a + b; + remB += -(remA - b - a); + + if (remA > 0.0) + break; + + // Remainder is negative, so decrement k and try again. + // This should only happen if the input is very close + // to an even multiple of pi/2 + k--; + } + quadrant = k & 3; + xa = remA; + xb = remB; + } + + if (xa > 1.5) { + // Accurracy suffers between 1.5 and PI/2 + final double pi2a = 1.5707963267948966; + final double pi2b = 6.123233995736766E-17; + + final double a = pi2a - xa; + double b = -(a - pi2a + xa); + b += pi2b - xb; + + xa = a + b; + xb = -(xa - a - b); + quadrant ^= 1; + negative ^= true; + } + + double result; + if ((quadrant & 1) == 0) { + result = tanQ(xa, xb, false); + } else { + result = -tanQ(xa, xb, true); + } + + if (negative) { + result = -result; + } + + return result; + } + + /** + * Arctangent function + * @param x a number + * @return atan(x) + */ + public static double atan(double x) { + return atan(x, 0.0, false); + } + + /** Internal helper function to compute arctangent. + * @param xa number from which arctangent is requested + * @param xb extra bits for x (may be 0.0) + * @param leftPlane if true, result angle must be put in the left half plane + * @return atan(xa + xb) (or angle shifted by {@code PI} if leftPlane is true) + */ + private static double atan(double xa, double xb, boolean leftPlane) { + boolean negate = false; + int idx; + + if (xa == 0.0) { // Matches +/- 0.0; return correct sign + return leftPlane ? copySign(Math.PI, xa) : xa; + } + + if (xa < 0) { + // negative + xa = -xa; + xb = -xb; + negate = true; + } + + if (xa > 1.633123935319537E16) { // Very large input + return (negate ^ leftPlane) ? (-Math.PI/2.0) : (Math.PI/2.0); + } + + /* Estimate the closest tabulated arctan value, compute eps = xa-tangentTable */ + if (xa < 1.0) { + idx = (int) (((-1.7168146928204136 * xa * xa + 8.0) * xa) + 0.5); + } else { + double temp = 1.0/xa; + idx = (int) (-((-1.7168146928204136 * temp * temp + 8.0) * temp) + 13.07); + } + double epsA = xa - TANGENT_TABLE_A[idx]; + double epsB = -(epsA - xa + TANGENT_TABLE_A[idx]); + epsB += xb - TANGENT_TABLE_B[idx]; + + double temp = epsA + epsB; + epsB = -(temp - epsA - epsB); + epsA = temp; + + /* Compute eps = eps / (1.0 + xa*tangent) */ + temp = xa * HEX_40000000; + double ya = xa + temp - temp; + double yb = xb + xa - ya; + xa = ya; + xb += yb; + + //if (idx > 8 || idx == 0) + if (idx == 0) { + /* If the slope of the arctan is gentle enough (< 0.45), this approximation will suffice */ + //double denom = 1.0 / (1.0 + xa*tangentTableA[idx] + xb*tangentTableA[idx] + xa*tangentTableB[idx] + xb*tangentTableB[idx]); + double denom = 1.0 / (1.0 + (xa + xb) * (TANGENT_TABLE_A[idx] + TANGENT_TABLE_B[idx])); + //double denom = 1.0 / (1.0 + xa*tangentTableA[idx]); + ya = epsA * denom; + yb = epsB * denom; + } else { + double temp2 = xa * TANGENT_TABLE_A[idx]; + double za = 1.0 + temp2; + double zb = -(za - 1.0 - temp2); + temp2 = xb * TANGENT_TABLE_A[idx] + xa * TANGENT_TABLE_B[idx]; + temp = za + temp2; + zb += -(temp - za - temp2); + za = temp; + + zb += xb * TANGENT_TABLE_B[idx]; + ya = epsA / za; + + temp = ya * HEX_40000000; + final double yaa = (ya + temp) - temp; + final double yab = ya - yaa; + + temp = za * HEX_40000000; + final double zaa = (za + temp) - temp; + final double zab = za - zaa; + + /* Correct for rounding in division */ + yb = (epsA - yaa * zaa - yaa * zab - yab * zaa - yab * zab) / za; + + yb += -epsA * zb / za / za; + yb += epsB / za; + } + + + epsA = ya; + epsB = yb; + + /* Evaluate polynomial */ + double epsA2 = epsA*epsA; + + /* + yb = -0.09001346640161823; + yb = yb * epsA2 + 0.11110718400605211; + yb = yb * epsA2 + -0.1428571349122913; + yb = yb * epsA2 + 0.19999999999273194; + yb = yb * epsA2 + -0.33333333333333093; + yb = yb * epsA2 * epsA; + */ + + yb = 0.07490822288864472; + yb = yb * epsA2 + -0.09088450866185192; + yb = yb * epsA2 + 0.11111095942313305; + yb = yb * epsA2 + -0.1428571423679182; + yb = yb * epsA2 + 0.19999999999923582; + yb = yb * epsA2 + -0.33333333333333287; + yb = yb * epsA2 * epsA; + + + ya = epsA; + + temp = ya + yb; + yb = -(temp - ya - yb); + ya = temp; + + /* Add in effect of epsB. atan'(x) = 1/(1+x^2) */ + yb += epsB / (1.0 + epsA * epsA); + + double result; + double resultb; + + //result = yb + eighths[idx] + ya; + double za = EIGHTHS[idx] + ya; + double zb = -(za - EIGHTHS[idx] - ya); + temp = za + yb; + zb += -(temp - za - yb); + za = temp; + + result = za + zb; + resultb = -(result - za - zb); + + if (leftPlane) { + // Result is in the left plane + final double pia = 1.5707963267948966*2.0; + final double pib = 6.123233995736766E-17*2.0; + + za = pia - result; + zb = -(za - pia + result); + zb += pib - resultb; + + result = za + zb; + resultb = -(result - za - zb); + } + + + if (negate ^ leftPlane) { + result = -result; + } + + return result; + } + + /** + * Two arguments arctangent function + * @param y ordinate + * @param x abscissa + * @return phase angle of point (x,y) between {@code -PI} and {@code PI} + */ + public static double atan2(double y, double x) { + if (x !=x || y != y) { + return Double.NaN; + } + + if (y == 0.0) { + double result = x*y; + double invx = 1.0/x; + double invy = 1.0/y; + + if (invx == 0.0) { // X is infinite + if (x > 0) { + return y; // return +/- 0.0 + } else { + return copySign(Math.PI, y); + } + } + + if (x < 0.0 || invx < 0.0) { + if (y < 0.0 || invy < 0.0) { + return -Math.PI; + } else { + return Math.PI; + } + } else { + return result; + } + } + + // y cannot now be zero + + if (y == Double.POSITIVE_INFINITY) { + if (x == Double.POSITIVE_INFINITY) { + return Math.PI/4.0; + } + + if (x == Double.NEGATIVE_INFINITY) { + return Math.PI*3.0/4.0; + } + + return Math.PI/2.0; + } + + if (y == Double.NEGATIVE_INFINITY) { + if (x == Double.POSITIVE_INFINITY) { + return -Math.PI/4.0; + } + + if (x == Double.NEGATIVE_INFINITY) { + return -Math.PI*3.0/4.0; + } + + return -Math.PI/2.0; + } + + if (x == Double.POSITIVE_INFINITY) { + if (y > 0.0 || 1/y > 0.0) { + return 0.0; + } + + if (y < 0.0 || 1/y < 0.0) { + return -0.0; + } + } + + if (x == Double.NEGATIVE_INFINITY) + { + if (y > 0.0 || 1/y > 0.0) { + return Math.PI; + } + + if (y < 0.0 || 1/y < 0.0) { + return -Math.PI; + } + } + + // Neither y nor x can be infinite or NAN here + + if (x == 0) { + if (y > 0.0 || 1/y > 0.0) { + return Math.PI/2.0; + } + + if (y < 0.0 || 1/y < 0.0) { + return -Math.PI/2.0; + } + } + + // Compute ratio r = y/x + final double r = y/x; + if (Double.isInfinite(r)) { // bypass calculations that can create NaN + return atan(r, 0, x < 0); + } + + double ra = doubleHighPart(r); + double rb = r - ra; + + // Split x + final double xa = doubleHighPart(x); + final double xb = x - xa; + + rb += (y - ra * xa - ra * xb - rb * xa - rb * xb) / x; + + double temp = ra + rb; + rb = -(temp - ra - rb); + ra = temp; + + if (ra == 0) { // Fix up the sign so atan works correctly + ra = copySign(0.0, y); + } + + // Call atan + double result = atan(ra, rb, x < 0); + + return result; + } + + /** Compute the arc sine of a number. + * @param x number on which evaluation is done + * @return arc sine of x + */ + public static double asin(double x) { + if (x != x) { + return Double.NaN; + } + + if (x > 1.0 || x < -1.0) { + return Double.NaN; + } + + if (x == 1.0) { + return Math.PI/2.0; + } + + if (x == -1.0) { + return -Math.PI/2.0; + } + + if (x == 0.0) { // Matches +/- 0.0; return correct sign + return x; + } + + /* Compute asin(x) = atan(x/sqrt(1-x*x)) */ + + /* Split x */ + double temp = x * HEX_40000000; + final double xa = x + temp - temp; + final double xb = x - xa; + + /* Square it */ + double ya = xa*xa; + double yb = xa*xb*2.0 + xb*xb; + + /* Subtract from 1 */ + ya = -ya; + yb = -yb; + + double za = 1.0 + ya; + double zb = -(za - 1.0 - ya); + + temp = za + yb; + zb += -(temp - za - yb); + za = temp; + + /* Square root */ + double y; + y = sqrt(za); + temp = y * HEX_40000000; + ya = y + temp - temp; + yb = y - ya; + + /* Extend precision of sqrt */ + yb += (za - ya*ya - 2*ya*yb - yb*yb) / (2.0*y); + + /* Contribution of zb to sqrt */ + double dx = zb / (2.0*y); + + // Compute ratio r = x/y + double r = x/y; + temp = r * HEX_40000000; + double ra = r + temp - temp; + double rb = r - ra; + + rb += (x - ra*ya - ra*yb - rb*ya - rb*yb) / y; // Correct for rounding in division + rb += -x * dx / y / y; // Add in effect additional bits of sqrt. + + temp = ra + rb; + rb = -(temp - ra - rb); + ra = temp; + + return atan(ra, rb, false); + } + + /** Compute the arc cosine of a number. + * @param x number on which evaluation is done + * @return arc cosine of x + */ + public static double acos(double x) { + if (x != x) { + return Double.NaN; + } + + if (x > 1.0 || x < -1.0) { + return Double.NaN; + } + + if (x == -1.0) { + return Math.PI; + } + + if (x == 1.0) { + return 0.0; + } + + if (x == 0) { + return Math.PI/2.0; + } + + /* Compute acos(x) = atan(sqrt(1-x*x)/x) */ + + /* Split x */ + double temp = x * HEX_40000000; + final double xa = x + temp - temp; + final double xb = x - xa; + + /* Square it */ + double ya = xa*xa; + double yb = xa*xb*2.0 + xb*xb; + + /* Subtract from 1 */ + ya = -ya; + yb = -yb; + + double za = 1.0 + ya; + double zb = -(za - 1.0 - ya); + + temp = za + yb; + zb += -(temp - za - yb); + za = temp; + + /* Square root */ + double y = sqrt(za); + temp = y * HEX_40000000; + ya = y + temp - temp; + yb = y - ya; + + /* Extend precision of sqrt */ + yb += (za - ya*ya - 2*ya*yb - yb*yb) / (2.0*y); + + /* Contribution of zb to sqrt */ + yb += zb / (2.0*y); + y = ya+yb; + yb = -(y - ya - yb); + + // Compute ratio r = y/x + double r = y/x; + + // Did r overflow? + if (Double.isInfinite(r)) { // x is effectively zero + return Math.PI/2; // so return the appropriate value + } + + double ra = doubleHighPart(r); + double rb = r - ra; + + rb += (y - ra*xa - ra*xb - rb*xa - rb*xb) / x; // Correct for rounding in division + rb += yb / x; // Add in effect additional bits of sqrt. + + temp = ra + rb; + rb = -(temp - ra - rb); + ra = temp; + + return atan(ra, rb, x<0); + } + + /** Compute the cubic root of a number. + * @param x number on which evaluation is done + * @return cubic root of x + */ + public static double cbrt(double x) { + /* Convert input double to bits */ + long inbits = Double.doubleToLongBits(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.doubleToLongBits(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; + } + + /** + * Convert degrees to radians, with error of less than 0.5 ULP + * @param x angle in degrees + * @return x converted into radians + */ + public static double toRadians(double x) + { + if (Double.isInfinite(x) || x == 0.0) { // Matches +/- 0.0; return correct sign + return x; + } + + // These are PI/180 split into high and low order bits + final double facta = 0.01745329052209854; + final double factb = 1.997844754509471E-9; + + double xa = doubleHighPart(x); + double xb = x - xa; + + double result = xb * factb + xb * facta + xa * factb + xa * facta; + if (result == 0) { + result = result * x; // ensure correct sign if calculation underflows + } + return result; + } + + /** + * Convert radians to degrees, with error of less than 0.5 ULP + * @param x angle in radians + * @return x converted into degrees + */ + public static double toDegrees(double x) + { + if (Double.isInfinite(x) || x == 0.0) { // Matches +/- 0.0; return correct sign + return x; + } + + // These are 180/PI split into high and low order bits + final double facta = 57.2957763671875; + final double factb = 3.145894820876798E-6; + + double xa = doubleHighPart(x); + double xb = x - xa; + + return xb * factb + xb * facta + xa * factb + xa * facta; + } + + /** + * Absolute value. + * @param x number from which absolute value is requested + * @return abs(x) + */ + public static int abs(final int x) { + return (x < 0) ? -x : x; + } + + /** + * Absolute value. + * @param x number from which absolute value is requested + * @return abs(x) + */ + public static long abs(final long x) { + return (x < 0l) ? -x : x; + } + + /** + * Absolute value. + * @param x number from which absolute value is requested + * @return abs(x) + */ + public static float abs(final float x) { + return (x < 0.0f) ? -x : (x == 0.0f) ? 0.0f : x; // -0.0 => +0.0 + } + + /** + * Absolute value. + * @param x number from which absolute value is requested + * @return abs(x) + */ + public static double abs(double x) { + return (x < 0.0) ? -x : (x == 0.0) ? 0.0 : x; // -0.0 => +0.0 + } + + /** + * Compute least significant bit (Unit in Last Position) for a number. + * @param x number from which ulp is requested + * @return ulp(x) + */ + public static double ulp(double x) { + if (Double.isInfinite(x)) { + return Double.POSITIVE_INFINITY; + } + return abs(x - Double.longBitsToDouble(Double.doubleToLongBits(x) ^ 1)); + } + + /** + * Compute least significant bit (Unit in Last Position) for a number. + * @param x number from which ulp is requested + * @return ulp(x) + */ + public static float ulp(float x) { + if (Float.isInfinite(x)) { + return Float.POSITIVE_INFINITY; + } + return abs(x - Float.intBitsToFloat(Float.floatToIntBits(x) ^ 1)); + } + + /** + * Multiply a double number by a power of 2. + * @param d number to multiply + * @param n power of 2 + * @return d × 2<sup>n</sup> + */ + public static double scalb(final double d, final int n) { + + // first simple and fast handling when 2^n can be represented using normal numbers + if ((n > -1023) && (n < 1024)) { + return d * Double.longBitsToDouble(((long) (n + 1023)) << 52); + } + + // handle special cases + if (Double.isNaN(d) || Double.isInfinite(d) || (d == 0)) { + return d; + } + if (n < -2098) { + return (d > 0) ? 0.0 : -0.0; + } + if (n > 2097) { + return (d > 0) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; + } + + // decompose d + final long bits = Double.doubleToLongBits(d); + final long sign = bits & 0x8000000000000000L; + int exponent = ((int) (bits >>> 52)) & 0x7ff; + long mantissa = bits & 0x000fffffffffffffL; + + // compute scaled exponent + int scaledExponent = exponent + n; + + if (n < 0) { + // we are really in the case n <= -1023 + if (scaledExponent > 0) { + // both the input and the result are normal numbers, we only adjust the exponent + return Double.longBitsToDouble(sign | (((long) scaledExponent) << 52) | mantissa); + } else if (scaledExponent > -53) { + // the input is a normal number and the result is a subnormal number + + // recover the hidden mantissa bit + mantissa = mantissa | (1L << 52); + + // scales down complete mantissa, hence losing least significant bits + final long mostSignificantLostBit = mantissa & (1L << (-scaledExponent)); + mantissa = mantissa >>> (1 - scaledExponent); + if (mostSignificantLostBit != 0) { + // we need to add 1 bit to round up the result + mantissa++; + } + return Double.longBitsToDouble(sign | mantissa); + + } else { + // no need to compute the mantissa, the number scales down to 0 + return (sign == 0L) ? 0.0 : -0.0; + } + } else { + // we are really in the case n >= 1024 + if (exponent == 0) { + + // the input number is subnormal, normalize it + while ((mantissa >>> 52) != 1) { + mantissa = mantissa << 1; + --scaledExponent; + } + ++scaledExponent; + mantissa = mantissa & 0x000fffffffffffffL; + + if (scaledExponent < 2047) { + return Double.longBitsToDouble(sign | (((long) scaledExponent) << 52) | mantissa); + } else { + return (sign == 0L) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; + } + + } else if (scaledExponent < 2047) { + return Double.longBitsToDouble(sign | (((long) scaledExponent) << 52) | mantissa); + } else { + return (sign == 0L) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; + } + } + + } + + /** + * Multiply a float number by a power of 2. + * @param f number to multiply + * @param n power of 2 + * @return f × 2<sup>n</sup> + */ + public static float scalb(final float f, final int n) { + + // first simple and fast handling when 2^n can be represented using normal numbers + if ((n > -127) && (n < 128)) { + return f * Float.intBitsToFloat((n + 127) << 23); + } + + // handle special cases + if (Float.isNaN(f) || Float.isInfinite(f) || (f == 0f)) { + return f; + } + if (n < -277) { + return (f > 0) ? 0.0f : -0.0f; + } + if (n > 276) { + return (f > 0) ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY; + } + + // decompose f + final int bits = Float.floatToIntBits(f); + final int sign = bits & 0x80000000; + int exponent = (bits >>> 23) & 0xff; + int mantissa = bits & 0x007fffff; + + // compute scaled exponent + int scaledExponent = exponent + n; + + if (n < 0) { + // we are really in the case n <= -127 + if (scaledExponent > 0) { + // both the input and the result are normal numbers, we only adjust the exponent + return Float.intBitsToFloat(sign | (scaledExponent << 23) | mantissa); + } else if (scaledExponent > -24) { + // the input is a normal number and the result is a subnormal number + + // recover the hidden mantissa bit + mantissa = mantissa | (1 << 23); + + // scales down complete mantissa, hence losing least significant bits + final int mostSignificantLostBit = mantissa & (1 << (-scaledExponent)); + mantissa = mantissa >>> (1 - scaledExponent); + if (mostSignificantLostBit != 0) { + // we need to add 1 bit to round up the result + mantissa++; + } + return Float.intBitsToFloat(sign | mantissa); + + } else { + // no need to compute the mantissa, the number scales down to 0 + return (sign == 0) ? 0.0f : -0.0f; + } + } else { + // we are really in the case n >= 128 + if (exponent == 0) { + + // the input number is subnormal, normalize it + while ((mantissa >>> 23) != 1) { + mantissa = mantissa << 1; + --scaledExponent; + } + ++scaledExponent; + mantissa = mantissa & 0x007fffff; + + if (scaledExponent < 255) { + return Float.intBitsToFloat(sign | (scaledExponent << 23) | mantissa); + } else { + return (sign == 0) ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY; + } + + } else if (scaledExponent < 255) { + return Float.intBitsToFloat(sign | (scaledExponent << 23) | mantissa); + } else { + return (sign == 0) ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY; + } + } + + } + + /** + * Get the next machine representable number after a number, moving + * in the direction of another number. + * <p> + * The ordering is as follows (increasing): + * <ul> + * <li>-INFINITY</li> + * <li>-MAX_VALUE</li> + * <li>-MIN_VALUE</li> + * <li>-0.0</li> + * <li>+0.0</li> + * <li>+MIN_VALUE</li> + * <li>+MAX_VALUE</li> + * <li>+INFINITY</li> + * <li></li> + * <p> + * If arguments compare equal, then the second argument is returned. + * <p> + * If {@code direction} is greater than {@code d}, + * the smallest machine representable number strictly greater than + * {@code d} is returned; if less, then the largest representable number + * strictly less than {@code d} is returned.</p> + * <p> + * If {@code d} is infinite and direction does not + * bring it back to finite numbers, it is returned unchanged.</p> + * + * @param d base number + * @param direction (the only important thing is whether + * {@code direction} is greater or smaller than {@code d}) + * @return the next machine representable number in the specified direction + */ + public static double nextAfter(double d, double direction) { + + // handling of some important special cases + if (Double.isNaN(d) || Double.isNaN(direction)) { + return Double.NaN; + } else if (d == direction) { + return direction; + } else if (Double.isInfinite(d)) { + return (d < 0) ? -Double.MAX_VALUE : Double.MAX_VALUE; + } else if (d == 0) { + return (direction < 0) ? -Double.MIN_VALUE : Double.MIN_VALUE; + } + // special cases MAX_VALUE to infinity and MIN_VALUE to 0 + // are handled just as normal numbers + + final long bits = Double.doubleToLongBits(d); + final long sign = bits & 0x8000000000000000L; + if ((direction < d) ^ (sign == 0L)) { + return Double.longBitsToDouble(sign | ((bits & 0x7fffffffffffffffL) + 1)); + } else { + return Double.longBitsToDouble(sign | ((bits & 0x7fffffffffffffffL) - 1)); + } + + } + + /** + * Get the next machine representable number after a number, moving + * in the direction of another number. + * <p> + * The ordering is as follows (increasing): + * <ul> + * <li>-INFINITY</li> + * <li>-MAX_VALUE</li> + * <li>-MIN_VALUE</li> + * <li>-0.0</li> + * <li>+0.0</li> + * <li>+MIN_VALUE</li> + * <li>+MAX_VALUE</li> + * <li>+INFINITY</li> + * <li></li> + * <p> + * If arguments compare equal, then the second argument is returned. + * <p> + * If {@code direction} is greater than {@code f}, + * the smallest machine representable number strictly greater than + * {@code f} is returned; if less, then the largest representable number + * strictly less than {@code f} is returned.</p> + * <p> + * If {@code f} is infinite and direction does not + * bring it back to finite numbers, it is returned unchanged.</p> + * + * @param f base number + * @param direction (the only important thing is whether + * {@code direction} is greater or smaller than {@code f}) + * @return the next machine representable number in the specified direction + */ + public static float nextAfter(final float f, final double direction) { + + // handling of some important special cases + if (Double.isNaN(f) || Double.isNaN(direction)) { + return Float.NaN; + } else if (f == direction) { + return (float) direction; + } else if (Float.isInfinite(f)) { + return (f < 0f) ? -Float.MAX_VALUE : Float.MAX_VALUE; + } else if (f == 0f) { + return (direction < 0) ? -Float.MIN_VALUE : Float.MIN_VALUE; + } + // special cases MAX_VALUE to infinity and MIN_VALUE to 0 + // are handled just as normal numbers + + final int bits = Float.floatToIntBits(f); + final int sign = bits & 0x80000000; + if ((direction < f) ^ (sign == 0)) { + return Float.intBitsToFloat(sign | ((bits & 0x7fffffff) + 1)); + } else { + return Float.intBitsToFloat(sign | ((bits & 0x7fffffff) - 1)); + } + + } + + /** Get the largest whole number smaller than x. + * @param x number from which floor is requested + * @return a double number f such that f is an integer f <= x < f + 1.0 + */ + public static double floor(double x) { + long y; + + if (x != x) { // NaN + return x; + } + + if (x >= TWO_POWER_52 || x <= -TWO_POWER_52) { + return x; + } + + y = (long) x; + if (x < 0 && y != x) { + y--; + } + + if (y == 0) { + return x*y; + } + + return y; + } + + /** Get the smallest whole number larger than x. + * @param x number from which ceil is requested + * @return a double number c such that c is an integer c - 1.0 < x <= c + */ + public static double ceil(double x) { + double y; + + if (x != x) { // NaN + return x; + } + + y = floor(x); + if (y == x) { + return y; + } + + y += 1.0; + + if (y == 0) { + return x*y; + } + + return y; + } + + /** Get the whole number that is the nearest to x, or the even one if x is exactly half way between two integers. + * @param x number from which nearest whole number is requested + * @return a double number r such that r is an integer r - 0.5 <= x <= r + 0.5 + */ + public static double rint(double x) { + double y = floor(x); + double d = x - y; + + if (d > 0.5) { + if (y == -1.0) { + return -0.0; // Preserve sign of operand + } + return y+1.0; + } + if (d < 0.5) { + return y; + } + + /* half way, round to even */ + long z = (long) y; + return (z & 1) == 0 ? y : y + 1.0; + } + + /** Get the closest long to x. + * @param x number from which closest long is requested + * @return closest long to x + */ + public static long round(double x) { + return (long) floor(x + 0.5); + } + + /** Get the closest int to x. + * @param x number from which closest int is requested + * @return closest int to x + */ + public static int round(final float x) { + return (int) floor(x + 0.5f); + } + + /** Compute the minimum of two values + * @param a first value + * @param b second value + * @return a if a is lesser or equal to b, b otherwise + */ + public static int min(final int a, final int b) { + return (a <= b) ? a : b; + } + + /** Compute the minimum of two values + * @param a first value + * @param b second value + * @return a if a is lesser or equal to b, b otherwise + */ + public static long min(final long a, final long b) { + return (a <= b) ? a : b; + } + + /** Compute the minimum of two values + * @param a first value + * @param b second value + * @return a if a is lesser or equal to b, b otherwise + */ + public static float min(final float a, final float b) { + if (a > b) { + return b; + } + if (a < b) { + return a; + } + /* if either arg is NaN, return NaN */ + if (a != b) { + return Float.NaN; + } + /* min(+0.0,-0.0) == -0.0 */ + /* 0x80000000 == Float.floatToRawIntBits(-0.0d) */ + int bits = Float.floatToRawIntBits(a); + if (bits == 0x80000000) { + return a; + } + return b; + } + + /** Compute the minimum of two values + * @param a first value + * @param b second value + * @return a if a is lesser or equal to b, b otherwise + */ + public static double min(final double a, final double b) { + if (a > b) { + return b; + } + if (a < b) { + return a; + } + /* if either arg is NaN, return NaN */ + if (a != b) { + return Double.NaN; + } + /* min(+0.0,-0.0) == -0.0 */ + /* 0x8000000000000000L == Double.doubleToRawLongBits(-0.0d) */ + long bits = Double.doubleToRawLongBits(a); + if (bits == 0x8000000000000000L) { + return a; + } + return b; + } + + /** Compute the maximum of two values + * @param a first value + * @param b second value + * @return b if a is lesser or equal to b, a otherwise + */ + public static int max(final int a, final int b) { + return (a <= b) ? b : a; + } + + /** Compute the maximum of two values + * @param a first value + * @param b second value + * @return b if a is lesser or equal to b, a otherwise + */ + public static long max(final long a, final long b) { + return (a <= b) ? b : a; + } + + /** Compute the maximum of two values + * @param a first value + * @param b second value + * @return b if a is lesser or equal to b, a otherwise + */ + public static float max(final float a, final float b) { + if (a > b) { + return a; + } + if (a < b) { + return b; + } + /* if either arg is NaN, return NaN */ + if (a != b) { + return Float.NaN; + } + /* min(+0.0,-0.0) == -0.0 */ + /* 0x80000000 == Float.floatToRawIntBits(-0.0d) */ + int bits = Float.floatToRawIntBits(a); + if (bits == 0x80000000) { + return b; + } + return a; + } + + /** Compute the maximum of two values + * @param a first value + * @param b second value + * @return b if a is lesser or equal to b, a otherwise + */ + public static double max(final double a, final double b) { + if (a > b) { + return a; + } + if (a < b) { + return b; + } + /* if either arg is NaN, return NaN */ + if (a != b) { + return Double.NaN; + } + /* min(+0.0,-0.0) == -0.0 */ + /* 0x8000000000000000L == Double.doubleToRawLongBits(-0.0d) */ + long bits = Double.doubleToRawLongBits(a); + if (bits == 0x8000000000000000L) { + return b; + } + return a; + } + + /** + * Returns the hypotenuse of a triangle with sides {@code x} and {@code y} + * - sqrt(<i>x</i><sup>2</sup> +<i>y</i><sup>2</sup>)<br/> + * avoiding intermediate overflow or underflow. + * + * <ul> + * <li> If either argument is infinite, then the result is positive infinity.</li> + * <li> else, if either argument is NaN then the result is NaN.</li> + * </ul> + * + * @param x a value + * @param y a value + * @return sqrt(<i>x</i><sup>2</sup> +<i>y</i><sup>2</sup>) + */ + public static double hypot(final double x, final double y) { + if (Double.isInfinite(x) || Double.isInfinite(y)) { + return Double.POSITIVE_INFINITY; + } else if (Double.isNaN(x) || Double.isNaN(y)) { + return Double.NaN; + } else { + + final int expX = getExponent(x); + final int expY = getExponent(y); + if (expX > expY + 27) { + // y is neglectible with respect to x + return abs(x); + } else if (expY > expX + 27) { + // x is neglectible with respect to y + return abs(y); + } else { + + // find an intermediate scale to avoid both overflow and underflow + final int middleExp = (expX + expY) / 2; + + // scale parameters without losing precision + final double scaledX = scalb(x, -middleExp); + final double scaledY = scalb(y, -middleExp); + + // compute scaled hypotenuse + final double scaledH = sqrt(scaledX * scaledX + scaledY * scaledY); + + // remove scaling + return scalb(scaledH, middleExp); + + } + + } + } + + /** + * Computes the remainder as prescribed by the IEEE 754 standard. + * The remainder value is mathematically equal to {@code x - y*n} + * where {@code n} is the mathematical integer closest to the exact mathematical value + * of the quotient {@code x/y}. + * If two mathematical integers are equally close to {@code x/y} then + * {@code n} is the integer that is even. + * <p> + * <ul> + * <li>If either operand is NaN, the result is NaN.</li> + * <li>If the result is not NaN, the sign of the result equals the sign of the dividend.</li> + * <li>If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN.</li> + * <li>If the dividend is finite and the divisor is an infinity, the result equals the dividend.</li> + * <li>If the dividend is a zero and the divisor is finite, the result equals the dividend.</li> + * </ul> + * <p><b>Note:</b> this implementation currently delegates to {@link StrictMath#IEEEremainder} + * @param dividend the number to be divided + * @param divisor the number by which to divide + * @return the remainder, rounded + */ + public static double IEEEremainder(double dividend, double divisor) { + return StrictMath.IEEEremainder(dividend, divisor); // TODO provide our own implementation + } + + /** + * Returns the first argument with the sign of the second argument. + * A NaN {@code sign} argument is treated as positive. + * + * @param magnitude the value to return + * @param sign the sign for the returned value + * @return the magnitude with the same sign as the {@code sign} argument + */ + public static double copySign(double magnitude, double sign){ + long m = Double.doubleToLongBits(magnitude); + long s = Double.doubleToLongBits(sign); + if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK + return magnitude; + } + return -magnitude; // flip sign + } + + /** + * Returns the first argument with the sign of the second argument. + * A NaN {@code sign} argument is treated as positive. + * + * @param magnitude the value to return + * @param sign the sign for the returned value + * @return the magnitude with the same sign as the {@code sign} argument + */ + public static float copySign(float magnitude, float sign){ + int m = Float.floatToIntBits(magnitude); + int s = Float.floatToIntBits(sign); + if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK + return magnitude; + } + return -magnitude; // flip sign + } + + /** + * Return the exponent of a double number, removing the bias. + * <p> + * For double numbers of the form 2<sup>x</sup>, the unbiased + * exponent is exactly x. + * </p> + * @param d number from which exponent is requested + * @return exponent for d in IEEE754 representation, without bias + */ + public static int getExponent(final double d) { + return (int) ((Double.doubleToLongBits(d) >>> 52) & 0x7ff) - 1023; + } + + /** + * Return the exponent of a float number, removing the bias. + * <p> + * For float numbers of the form 2<sup>x</sup>, the unbiased + * exponent is exactly x. + * </p> + * @param f number from which exponent is requested + * @return exponent for d in IEEE754 representation, without bias + */ + public static int getExponent(final float f) { + return ((Float.floatToIntBits(f) >>> 23) & 0xff) - 127; + } + +} |