diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math3/util/FastMath.java')
-rw-r--r-- | src/main/java/org/apache/commons/math3/util/FastMath.java | 4508 |
1 files changed, 4508 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/util/FastMath.java b/src/main/java/org/apache/commons/math3/util/FastMath.java new file mode 100644 index 0000000..f40961e --- /dev/null +++ b/src/main/java/org/apache/commons/math3/util/FastMath.java @@ -0,0 +1,4508 @@ +/* + * 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.math3.util; + +import org.apache.commons.math3.exception.MathArithmeticException; +import org.apache.commons.math3.exception.util.LocalizedFormats; + +import java.io.PrintStream; + +/** + * Faster, more accurate, portable alternative to {@link Math} and {@link StrictMath} for large + * scale computation. + * + * <p>FastMath is a drop-in replacement for both Math and StrictMath. This means that for any method + * in Math (say {@code Math.sin(x)} or {@code Math.cbrt(y)}), user can directly change the class and + * use the methods as is (using {@code FastMath.sin(x)} or {@code FastMath.cbrt(y)} in the previous + * example). + * + * <p>FastMath speed is achieved by relying heavily on optimizing compilers to native code present + * in many JVMs today and use of large tables. The larger tables are lazily initialised on first + * use, so that the setup time does not penalise methods that don't need them. + * + * <p>Note that FastMath is extensively used inside Apache Commons Math, so by calling some + * algorithms, the overhead when the the tables need to be intialised will occur regardless of the + * end-user calling FastMath methods directly or not. Performance figures for a specific JVM and + * hardware can be evaluated by running the FastMathTestPerformance tests in the test directory of + * the source distribution. + * + * <p>FastMath accuracy should be mostly independent of the JVM as it relies only on IEEE-754 basic + * operations and on embedded tables. Almost all operations are accurate to about 0.5 ulp throughout + * the domain range. This statement, of course is only a rough global observed behavior, it is + * <em>not</em> a guarantee for <em>every</em> double numbers input (see William Kahan's <a + * href="http://en.wikipedia.org/wiki/Rounding#The_table-maker.27s_dilemma">Table Maker's + * Dilemma</a>). + * + * <p>FastMath additionally implements the following methods not found in Math/StrictMath: + * + * <ul> + * <li>{@link #asinh(double)} + * <li>{@link #acosh(double)} + * <li>{@link #atanh(double)} + * </ul> + * + * The following methods are found in Math/StrictMath since 1.6 only, they are provided by FastMath + * even in 1.5 Java virtual machines + * + * <ul> + * <li>{@link #copySign(double, double)} + * <li>{@link #getExponent(double)} + * <li>{@link #nextAfter(double,double)} + * <li>{@link #nextUp(double)} + * <li>{@link #scalb(double, int)} + * <li>{@link #copySign(float, float)} + * <li>{@link #getExponent(float)} + * <li>{@link #nextAfter(float,double)} + * <li>{@link #nextUp(float)} + * <li>{@link #scalb(float, int)} + * </ul> + * + * @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; + + /** Index of exp(0) in the array of integer exponentials. */ + static final int EXP_INT_TABLE_MAX_INDEX = 750; + + /** Length of the array of integer exponentials. */ + static final int EXP_INT_TABLE_LEN = EXP_INT_TABLE_MAX_INDEX * 2; + + /** Logarithm table length. */ + static final int LN_MANT_LEN = 1024; + + /** Exponential fractions table length. */ + static final int EXP_FRAC_TABLE_LEN = 1025; // 0, 1/1024, ... 1024/1024 + + /** StrictMath.log(Double.MAX_VALUE): {@value} */ + private static final double LOG_MAX_VALUE = StrictMath.log(Double.MAX_VALUE); + + /** + * Indicator for tables initialization. + * + * <p>This compile-time constant should be set to true only if one explicitly wants to compute + * the tables at class loading time instead of using the already computed ones provided as + * literal arrays below. + */ + private static final boolean RECOMPUTE_TABLES_AT_RUNTIME = false; + + /** log(2) (high bits). */ + private static final double LN_2_A = 0.693147063255310059; + + /** log(2) (low bits). */ + private static final double LN_2_B = 1.17304635250823482e-7; + + /** Coefficients for log, when input 0.99 < x < 1.01. */ + private static final double LN_QUICK_COEF[][] = { + {1.0, 5.669184079525E-24}, + {-0.25, -0.25}, + {0.3333333134651184, 1.986821492305628E-8}, + {-0.25, -6.663542893624021E-14}, + {0.19999998807907104, 1.1921056801463227E-8}, + {-0.1666666567325592, -7.800414592973399E-9}, + {0.1428571343421936, 5.650007086920087E-9}, + {-0.12502530217170715, -7.44321345601866E-11}, + {0.11113807559013367, 9.219544613762692E-9}, + }; + + /** Coefficients for log in the range of 1.0 < x < 1.0 + 2^-10. */ + private static final double LN_HI_PREC_COEF[][] = { + {1.0, -6.032174644509064E-23}, + {-0.25, -0.25}, + {0.3333333134651184, 1.9868161777724352E-8}, + {-0.2499999701976776, -2.957007209750105E-8}, + {0.19999954104423523, 1.5830993332061267E-10}, + {-0.16624879837036133, -2.6033824355191673E-8} + }; + + /** Sine, Cosine, Tangent tables are for 0, 1/8, 2/8, ... 13/8 = PI/2 approx. */ + private static final int SINE_TABLE_LEN = 14; + + /** Sine table (high bits). */ + private static final double SINE_TABLE_A[] = { + +0.0d, + +0.1246747374534607d, + +0.24740394949913025d, + +0.366272509098053d, + +0.4794255495071411d, + +0.5850973129272461d, + +0.6816387176513672d, + +0.7675435543060303d, + +0.8414709568023682d, + +0.902267575263977d, + +0.9489846229553223d, + +0.9808930158615112d, + +0.9974949359893799d, + +0.9985313415527344d, + }; + + /** Sine table (low bits). */ + private static final double SINE_TABLE_B[] = { + +0.0d, + -4.068233003401932E-9d, + +9.755392680573412E-9d, + +1.9987994582857286E-8d, + -1.0902938113007961E-8d, + -3.9986783938944604E-8d, + +4.23719669792332E-8d, + -5.207000323380292E-8d, + +2.800552834259E-8d, + +1.883511811213715E-8d, + -3.5997360512765566E-9d, + +4.116164446561962E-8d, + +5.0614674548127384E-8d, + -1.0129027912496858E-9d, + }; + + /** Cosine table (high bits). */ + private static final double COSINE_TABLE_A[] = { + +1.0d, + +0.9921976327896118d, + +0.9689123630523682d, + +0.9305076599121094d, + +0.8775825500488281d, + +0.8109631538391113d, + +0.7316888570785522d, + +0.6409968137741089d, + +0.5403022766113281d, + +0.4311765432357788d, + +0.3153223395347595d, + +0.19454771280288696d, + +0.07073719799518585d, + -0.05417713522911072d, + }; + + /** Cosine table (low bits). */ + private static final double COSINE_TABLE_B[] = { + +0.0d, + +3.4439717236742845E-8d, + +5.865827662008209E-8d, + -3.7999795083850525E-8d, + +1.184154459111628E-8d, + -3.43338934259355E-8d, + +1.1795268640216787E-8d, + +4.438921624363781E-8d, + +2.925681159240093E-8d, + -2.6437112632041807E-8d, + +2.2860509143963117E-8d, + -4.813899778443457E-9d, + +3.6725170580355583E-9d, + +2.0217439756338078E-10d, + }; + + /** Tangent table, used by atan() (high bits). */ + private static final double TANGENT_TABLE_A[] = { + +0.0d, + +0.1256551444530487d, + +0.25534194707870483d, + +0.3936265707015991d, + +0.5463024377822876d, + +0.7214844226837158d, + +0.9315965175628662d, + +1.1974215507507324d, + +1.5574076175689697d, + +2.092571258544922d, + +3.0095696449279785d, + +5.041914939880371d, + +14.101419448852539d, + -18.430862426757812d, + }; + + /** Tangent table, used by atan() (low bits). */ + private static final double TANGENT_TABLE_B[] = { + +0.0d, + -7.877917738262007E-9d, + -2.5857668567479893E-8d, + +5.2240336371356666E-9d, + +5.206150291559893E-8d, + +1.8307188599677033E-8d, + -5.7618793749770706E-8d, + +7.848361555046424E-8d, + +1.0708593250394448E-7d, + +1.7827257129423813E-8d, + +2.893485277253286E-8d, + +3.1660099222737955E-7d, + +4.983191803254889E-7d, + -3.356118100840571E-7d, + }; + + /** 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; + + /** Mask used to clear the non-sign part of an int. */ + private static final int MASK_NON_SIGN_INT = 0x7fffffff; + + /** Mask used to clear the non-sign part of a long. */ + private static final long MASK_NON_SIGN_LONG = 0x7fffffffffffffffl; + + /** Mask used to extract exponent from double bits. */ + private static final long MASK_DOUBLE_EXPONENT = 0x7ff0000000000000L; + + /** Mask used to extract mantissa from double bits. */ + private static final long MASK_DOUBLE_MANTISSA = 0x000fffffffffffffL; + + /** Mask used to add implicit high order bit for normalized double. */ + private static final long IMPLICIT_HIGH_BIT = 0x0010000000000000L; + + /** 2^52 - double numbers this large must be integral (no fraction) or NaN or Infinite */ + private static final double TWO_POWER_52 = 4503599627370496.0; + + /** Constant: {@value}. */ + private static final double F_1_3 = 1d / 3d; + + /** Constant: {@value}. */ + private static final double F_1_5 = 1d / 5d; + + /** Constant: {@value}. */ + private static final double F_1_7 = 1d / 7d; + + /** Constant: {@value}. */ + private static final double F_1_9 = 1d / 9d; + + /** Constant: {@value}. */ + private static final double F_1_11 = 1d / 11d; + + /** Constant: {@value}. */ + private static final double F_1_13 = 1d / 13d; + + /** Constant: {@value}. */ + private static final double F_1_15 = 1d / 15d; + + /** Constant: {@value}. */ + private static final double F_1_17 = 1d / 17d; + + /** Constant: {@value}. */ + private static final double F_3_4 = 3d / 4d; + + /** Constant: {@value}. */ + private static final double F_15_16 = 15d / 16d; + + /** Constant: {@value}. */ + private static final double F_13_14 = 13d / 14d; + + /** Constant: {@value}. */ + private static final double F_11_12 = 11d / 12d; + + /** Constant: {@value}. */ + private static final double F_9_10 = 9d / 10d; + + /** Constant: {@value}. */ + private static final double F_7_8 = 7d / 8d; + + /** Constant: {@value}. */ + private static final double F_5_6 = 5d / 6d; + + /** Constant: {@value}. */ + private static final double F_1_2 = 1d / 2d; + + /** Constant: {@value}. */ + private static final double F_1_4 = 1d / 4d; + + /** 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 > -Precision.SAFE_MIN && d < Precision.SAFE_MIN) { + return d; // These are un-normalised - don't try to convert + } + long xl = + Double.doubleToRawLongBits( + d); // can take raw bits because just gonna convert it back + 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; + } + + // cosh[z] = (exp(z) + exp(-z))/2 + + // for numbers with magnitude 20 or so, + // exp(-z) can be ignored in comparison with exp(z) + + if (x > 20) { + if (x >= LOG_MAX_VALUE) { + // Avoid overflow (MATH-905). + final double t = exp(0.5 * x); + return (0.5 * t) * t; + } else { + return 0.5 * exp(x); + } + } else if (x < -20) { + if (x <= -LOG_MAX_VALUE) { + // Avoid overflow (MATH-905). + final double t = exp(-0.5 * x); + return (0.5 * t) * t; + } else { + return 0.5 * exp(-x); + } + } + + final double hiPrec[] = new double[2]; + if (x < 0.0) { + x = -x; + } + exp(x, 0.0, hiPrec); + + double ya = hiPrec[0] + hiPrec[1]; + double yb = -(ya - hiPrec[0] - hiPrec[1]); + + double temp = ya * HEX_40000000; + double yaa = ya + temp - temp; + double yab = ya - yaa; + + // recip = 1/y + double recip = 1.0 / ya; + temp = recip * HEX_40000000; + double recipa = recip + temp - temp; + double recipb = recip - recipa; + + // Correct for rounding in division + recipb += (1.0 - yaa * recipa - yaa * recipb - yab * recipa - yab * recipb) * recip; + // Account for yb + recipb += -yb * recip * recip; + + // y = y + 1/y + temp = ya + recipa; + yb += -(temp - ya - recipa); + ya = temp; + temp = ya + recipb; + yb += -(temp - ya - recipb); + ya = temp; + + double result = ya + yb; + result *= 0.5; + return result; + } + + /** + * Compute the hyperbolic sine of a number. + * + * @param x number on which evaluation is done + * @return hyperbolic sine of x + */ + public static double sinh(double x) { + boolean negate = false; + if (x != x) { + return x; + } + + // sinh[z] = (exp(z) - exp(-z) / 2 + + // for values of z larger than about 20, + // exp(-z) can be ignored in comparison with exp(z) + + if (x > 20) { + if (x >= LOG_MAX_VALUE) { + // Avoid overflow (MATH-905). + final double t = exp(0.5 * x); + return (0.5 * t) * t; + } else { + return 0.5 * exp(x); + } + } else if (x < -20) { + if (x <= -LOG_MAX_VALUE) { + // Avoid overflow (MATH-905). + final double t = exp(-0.5 * x); + return (-0.5 * t) * t; + } else { + return -0.5 * exp(-x); + } + } + + if (x == 0) { + return x; + } + + if (x < 0.0) { + x = -x; + negate = true; + } + + double result; + + if (x > 0.25) { + double hiPrec[] = new double[2]; + exp(x, 0.0, hiPrec); + + double ya = hiPrec[0] + hiPrec[1]; + double yb = -(ya - hiPrec[0] - hiPrec[1]); + + double temp = ya * HEX_40000000; + double yaa = ya + temp - temp; + double yab = ya - yaa; + + // recip = 1/y + double recip = 1.0 / ya; + temp = recip * HEX_40000000; + double recipa = recip + temp - temp; + double recipb = recip - recipa; + + // Correct for rounding in division + recipb += (1.0 - yaa * recipa - yaa * recipb - yab * recipa - yab * recipb) * recip; + // Account for yb + recipb += -yb * recip * recip; + + recipa = -recipa; + recipb = -recipb; + + // y = y + 1/y + temp = ya + recipa; + yb += -(temp - ya - recipa); + ya = temp; + temp = ya + recipb; + yb += -(temp - ya - recipb); + ya = temp; + + result = ya + yb; + result *= 0.5; + } else { + double hiPrec[] = new double[2]; + expm1(x, hiPrec); + + double ya = hiPrec[0] + hiPrec[1]; + double yb = -(ya - hiPrec[0] - hiPrec[1]); + + /* Compute expm1(-x) = -expm1(x) / (expm1(x) + 1) */ + double denom = 1.0 + ya; + double denomr = 1.0 / denom; + double denomb = -(denom - 1.0 - ya) + yb; + double ratio = ya * denomr; + double temp = ratio * HEX_40000000; + double ra = ratio + temp - temp; + double rb = ratio - ra; + + temp = denom * HEX_40000000; + double za = denom + temp - temp; + double zb = denom - za; + + rb += (ya - za * ra - za * rb - zb * ra - zb * rb) * denomr; + + // Adjust for yb + rb += yb * denomr; // numerator + rb += -ya * denomb * denomr * denomr; // denominator + + // y = y - 1/y + temp = ya + ra; + yb += -(temp - ya - ra); + ya = temp; + temp = ya + rb; + yb += -(temp - ya - rb); + ya = temp; + + result = ya + yb; + result *= 0.5; + } + + if (negate) { + result = -result; + } + + return result; + } + + /** + * Compute the hyperbolic tangent of a number. + * + * @param x number on which evaluation is done + * @return hyperbolic tangent of x + */ + public static double tanh(double x) { + boolean negate = false; + + if (x != x) { + return x; + } + + // tanh[z] = sinh[z] / cosh[z] + // = (exp(z) - exp(-z)) / (exp(z) + exp(-z)) + // = (exp(2x) - 1) / (exp(2x) + 1) + + // for magnitude > 20, sinh[z] == cosh[z] in double precision + + if (x > 20.0) { + return 1.0; + } + + if (x < -20) { + return -1.0; + } + + if (x == 0) { + return x; + } + + if (x < 0.0) { + x = -x; + negate = true; + } + + double result; + if (x >= 0.5) { + double hiPrec[] = new double[2]; + // tanh(x) = (exp(2x) - 1) / (exp(2x) + 1) + exp(x * 2.0, 0.0, hiPrec); + + double ya = hiPrec[0] + hiPrec[1]; + double yb = -(ya - hiPrec[0] - hiPrec[1]); + + /* Numerator */ + double na = -1.0 + ya; + double nb = -(na + 1.0 - ya); + double temp = na + yb; + nb += -(temp - na - yb); + na = temp; + + /* Denominator */ + double da = 1.0 + ya; + double db = -(da - 1.0 - ya); + temp = da + yb; + db += -(temp - da - yb); + da = temp; + + temp = da * HEX_40000000; + double daa = da + temp - temp; + double dab = da - daa; + + // ratio = na/da + double ratio = na / da; + temp = ratio * HEX_40000000; + double ratioa = ratio + temp - temp; + double ratiob = ratio - ratioa; + + // Correct for rounding in division + ratiob += (na - daa * ratioa - daa * ratiob - dab * ratioa - dab * ratiob) / da; + + // Account for nb + ratiob += nb / da; + // Account for db + ratiob += -db * na / da / da; + + result = ratioa + ratiob; + } else { + double hiPrec[] = new double[2]; + // tanh(x) = expm1(2x) / (expm1(2x) + 2) + expm1(x * 2.0, hiPrec); + + double ya = hiPrec[0] + hiPrec[1]; + double yb = -(ya - hiPrec[0] - hiPrec[1]); + + /* Numerator */ + double na = ya; + double nb = yb; + + /* Denominator */ + double da = 2.0 + ya; + double db = -(da - 2.0 - ya); + double temp = da + yb; + db += -(temp - da - yb); + da = temp; + + temp = da * HEX_40000000; + double daa = da + temp - temp; + double dab = da - daa; + + // ratio = na/da + double ratio = na / da; + temp = ratio * HEX_40000000; + double ratioa = ratio + temp - temp; + double ratiob = ratio - ratioa; + + // Correct for rounding in division + ratiob += (na - daa * ratioa - daa * ratiob - dab * ratioa - dab * ratiob) / da; + + // Account for nb + ratiob += nb / da; + // Account for db + ratiob += -db * na / da / da; + + result = ratioa + ratiob; + } + + if (negate) { + result = -result; + } + + return result; + } + + /** + * Compute the 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 + * (F_1_3 + - a2 + * (F_1_5 + - a2 + * (F_1_7 + - a2 + * (F_1_9 + - a2 + * (F_1_11 + - a2 + * (F_1_13 + - a2 + * (F_1_15 + - a2 + * F_1_17 + * F_15_16) + * F_13_14) + * F_11_12) + * F_9_10) + * F_7_8) + * F_5_6) + * F_3_4) + * F_1_2); + } else if (a > 0.036) { + absAsinh = + a + * (1 + - a2 + * (F_1_3 + - a2 + * (F_1_5 + - a2 + * (F_1_7 + - a2 + * (F_1_9 + - a2 + * (F_1_11 + - a2 + * F_1_13 + * F_11_12) + * F_9_10) + * F_7_8) + * F_5_6) + * F_3_4) + * F_1_2); + } else if (a > 0.0036) { + absAsinh = + a + * (1 + - a2 + * (F_1_3 + - a2 + * (F_1_5 + - a2 + * (F_1_7 + - a2 * F_1_9 + * F_7_8) + * F_5_6) + * F_3_4) + * F_1_2); + } else { + absAsinh = a * (1 - a2 * (F_1_3 - a2 * F_1_5 * F_3_4) * F_1_2); + } + } + + 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 + * (F_1_3 + + a2 + * (F_1_5 + + a2 + * (F_1_7 + + a2 + * (F_1_9 + + a2 + * (F_1_11 + + a2 + * (F_1_13 + + a2 + * (F_1_15 + + a2 + * F_1_17)))))))); + } else if (a > 0.031) { + absAtanh = + a + * (1 + + a2 + * (F_1_3 + + a2 + * (F_1_5 + + a2 + * (F_1_7 + + a2 + * (F_1_9 + + a2 + * (F_1_11 + + a2 + * F_1_13)))))); + } else if (a > 0.003) { + absAtanh = a * (1 + a2 * (F_1_3 + a2 * (F_1_5 + a2 * (F_1_7 + a2 * F_1_9)))); + } else { + absAtanh = a * (1 + a2 * (F_1_3 + a2 * F_1_5)); + } + } + + 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); + } + + /** + * Compute next number towards negative infinity. + * + * @param a number to which neighbor should be computed + * @return neighbor of a towards negative infinity + * @since 3.4 + */ + public static double nextDown(final double a) { + return nextAfter(a, Double.NEGATIVE_INFINITY); + } + + /** + * Compute next number towards negative infinity. + * + * @param a number to which neighbor should be computed + * @return neighbor of a towards negative infinity + * @since 3.4 + */ + public static float nextDown(final float a) { + return nextAfter(a, Float.NEGATIVE_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. + * + * <p>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 ULP error. + * + * <p>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) + * + * <p>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 = (int) x; + + /* Lookup exp(floor(x)). + * intPartA will have the upper 22 bits, intPartB will have the lower + * 52 bits. + */ + if (x < 0.0) { + + // We don't check against intVal here as conversion of large negative double values + // may be affected by a JIT bug. Subsequent comparisons can safely use intVal + if (x < -746d) { + 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--; + + } else { + if (intVal > 709) { + if (hiPrec != null) { + hiPrec[0] = Double.POSITIVE_INFINITY; + hiPrec[1] = 0.0; + } + return Double.POSITIVE_INFINITY; + } + } + + intPartA = ExpIntTable.EXP_INT_TABLE_A[EXP_INT_TABLE_MAX_INDEX + intVal]; + intPartB = ExpIntTable.EXP_INT_TABLE_B[EXP_INT_TABLE_MAX_INDEX + intVal]; + + /* Get the fractional part of x, find the greatest multiple of 2^-10 less than + * x and look up the exp function of it. + * fracPartA will have the upper 22 bits, fracPartB the lower 52 bits. + */ + final int intFrac = (int) ((x - intVal) * 1024.0); + final double fracPartA = ExpFracTable.EXP_FRAC_TABLE_A[intFrac]; + final double fracPartB = ExpFracTable.EXP_FRAC_TABLE_B[intFrac]; + + /* epsilon is the difference in x from the nearest multiple of 2^-10. It + * has a value in the range 0 <= epsilon < 2^-10. + * Do the subtraction from x as the last step to avoid possible loss of precision. + */ + final double epsilon = x - (intVal + intFrac / 1024.0); + + /* Compute z = exp(epsilon) - 1.0 via a minimax polynomial. z has + full double precision (52 bits). Since z < 2^-10, we will have + 62 bits of precision when combined with the constant 1. This will be + used in the last addition below to get proper rounding. */ + + /* Remez generated polynomial. Converges on the interval [0, 2^-10], error + is less than 0.5 ULP */ + double z = 0.04168701738764507; + z = z * epsilon + 0.1666666505023083; + z = z * epsilon + 0.5000000000042687; + z = z * epsilon + 1.0; + z = z * epsilon + -3.940510424527919E-20; + + /* Compute (intPartA+intPartB) * (fracPartA+fracPartB) by binomial + expansion. + tempA is exact since intPartA and intPartB only have 22 bits each. + tempB will have 52 bits of precision. + */ + double tempA = intPartA * fracPartA; + double tempB = intPartA * fracPartB + intPartB * fracPartA + intPartB * fracPartB; + + /* Compute the result. (1+z)(tempA+tempB). Order of operations is + important. For accuracy add by increasing size. tempA is exact and + much larger than the others. If there are extra bits specified from the + pow() function, use them. */ + final double tempC = tempB + tempA; + + // If tempC is positive infinite, the evaluation below could result in NaN, + // because z could be negative at the same time. + if (tempC == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + 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 = ExpFracTable.EXP_FRAC_TABLE_A[intFrac] - 1.0; + double tempB = ExpFracTable.EXP_FRAC_TABLE_B[intFrac]; + + double temp = tempA + tempB; + tempB = -(temp - tempA - tempB); + tempA = temp; + + temp = tempA * HEX_40000000; + baseA = tempA + temp - temp; + baseB = tempB + (tempA - baseA); + + epsilon = x - intFrac / 1024.0; + } + + /* Compute expm1(epsilon) */ + double zb = 0.008336750013465571; + zb = zb * epsilon + 0.041666663879186654; + zb = zb * epsilon + 0.16666666666745392; + zb = zb * epsilon + 0.49999999999999994; + zb *= epsilon; + 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; + } + + /** + * 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.doubleToRawLongBits(x); + + /* Handle special cases of negative input, and NaN */ + if (((bits & 0x8000000000000000L) != 0 || x != x) && x != 0.0) { + if (hiPrec != null) { + hiPrec[0] = Double.NaN; + } + + return Double.NaN; + } + + /* Handle special cases of Positive infinity. */ + if (x == Double.POSITIVE_INFINITY) { + if (hiPrec != null) { + hiPrec[0] = Double.POSITIVE_INFINITY; + } + + return Double.POSITIVE_INFINITY; + } + + /* Extract the exponent */ + int exp = (int) (bits >> 52) - 1023; + + if ((bits & 0x7ff0000000000000L) == 0) { + // Subnormal! + if (x == 0) { + // Zero + if (hiPrec != null) { + hiPrec[0] = Double.NEGATIVE_INFINITY; + } + + return Double.NEGATIVE_INFINITY; + } + + /* Normalize the subnormal number. */ + bits <<= 1; + while ((bits & 0x0010000000000000L) == 0) { + --exp; + bits <<= 1; + } + } + + if ((exp == -1 || exp == 0) && x < 1.01 && x > 0.99 && hiPrec == null) { + /* The normal method doesn't work well in the range [0.99, 1.01], so call do a straight + polynomial expansion in higer precision. */ + + /* Compute x - 1.0 and split it */ + double xa = x - 1.0; + double xb = xa - x + 1.0; + double tmp = xa * HEX_40000000; + double aa = xa + tmp - tmp; + double ab = xa - aa; + xa = aa; + xb = ab; + + final double[] lnCoef_last = LN_QUICK_COEF[LN_QUICK_COEF.length - 1]; + double ya = lnCoef_last[0]; + double yb = lnCoef_last[1]; + + for (int i = LN_QUICK_COEF.length - 2; i >= 0; i--) { + /* Multiply a = y * x */ + aa = ya * xa; + ab = ya * xb + yb * xa + yb * xb; + /* split, so now y = a */ + tmp = aa * HEX_40000000; + ya = aa + tmp - tmp; + yb = aa - ya + ab; + + /* Add a = y + lnQuickCoef */ + final double[] lnCoef_i = LN_QUICK_COEF[i]; + aa = ya + lnCoef_i[0]; + ab = yb + lnCoef_i[1]; + /* Split y = a */ + tmp = aa * HEX_40000000; + ya = aa + tmp - tmp; + yb = aa - ya + ab; + } + + /* Multiply a = y * x */ + aa = ya * xa; + ab = ya * xb + yb * xa + yb * xb; + /* split, so now y = a */ + tmp = aa * HEX_40000000; + ya = aa + tmp - tmp; + yb = aa - ya + ab; + + return ya + yb; + } + + // lnm is a log of a number in the range of 1.0 - 2.0, so 0 <= lnm < ln(2) + final double[] lnm = lnMant.LN_MANT[(int) ((bits & 0x000ffc0000000000L) >> 42)]; + + /* + double epsilon = x / Double.longBitsToDouble(bits & 0xfffffc0000000000L); + + epsilon -= 1.0; + */ + + // y is the most significant 10 bits of the mantissa + // double y = Double.longBitsToDouble(bits & 0xfffffc0000000000L); + // double epsilon = (x - y) / y; + final double epsilon = + (bits & 0x3ffffffffffL) / (TWO_POWER_52 + (bits & 0x000ffc0000000000L)); + + double lnza = 0.0; + double lnzb = 0.0; + + if (hiPrec != null) { + /* split epsilon -> x */ + double tmp = epsilon * HEX_40000000; + double aa = epsilon + tmp - tmp; + double ab = epsilon - aa; + double xa = aa; + double xb = ab; + + /* Need a more accurate epsilon, so adjust the division. */ + final double numer = bits & 0x3ffffffffffL; + final double denom = TWO_POWER_52 + (bits & 0x000ffc0000000000L); + aa = numer - xa * denom - xb * denom; + xb += aa / denom; + + /* Remez polynomial evaluation */ + final double[] lnCoef_last = LN_HI_PREC_COEF[LN_HI_PREC_COEF.length - 1]; + double ya = lnCoef_last[0]; + double yb = lnCoef_last[1]; + + for (int i = LN_HI_PREC_COEF.length - 2; i >= 0; i--) { + /* Multiply a = y * x */ + aa = ya * xa; + ab = ya * xb + yb * xa + yb * xb; + /* split, so now y = a */ + tmp = aa * HEX_40000000; + ya = aa + tmp - tmp; + yb = aa - ya + ab; + + /* Add a = y + lnHiPrecCoef */ + final double[] lnCoef_i = LN_HI_PREC_COEF[i]; + aa = ya + lnCoef_i[0]; + ab = yb + lnCoef_i[1]; + /* Split y = a */ + tmp = aa * HEX_40000000; + ya = aa + tmp - tmp; + yb = aa - ya + ab; + } + + /* Multiply a = y * x */ + aa = ya * xa; + ab = ya * xb + yb * xa + yb * xb; + + /* split, so now lnz = a */ + /* + tmp = aa * 1073741824.0; + lnza = aa + tmp - tmp; + lnzb = aa - lnza + ab; + */ + lnza = aa + ab; + lnzb = -(lnza - aa - ab); + } else { + /* High precision not required. Eval Remez polynomial + using standard double precision */ + lnza = -0.16624882440418567; + lnza = lnza * epsilon + 0.19999954120254515; + lnza = lnza * epsilon + -0.2499999997677497; + lnza = lnza * epsilon + 0.3333333333332802; + lnza = lnza * epsilon + -0.5; + lnza = lnza * epsilon + 1.0; + lnza *= 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 += d; + + c = a + lnza; + d = -(c - a - lnza); + a = c; + b += d; + + c = a + LN_2_B * exp; + d = -(c - a - LN_2_B * exp); + a = c; + b += d; + + c = a + lnm[1]; + d = -(c - a - lnm[1]); + a = c; + b += d; + + c = a + lnzb; + d = -(c - a - lnzb); + a = c; + b += d; + + if (hiPrec != null) { + hiPrec[0] = a; + hiPrec[1] = b; + } + + return a + b; + } + + /** + * Computes log(1 + x). + * + * @param x Number. + * @return {@code log(1 + x)}. + */ + public static double log1p(final double x) { + if (x == -1) { + return Double.NEGATIVE_INFINITY; + } + + if (x == Double.POSITIVE_INFINITY) { + return Double.POSITIVE_INFINITY; + } + + if (x > 1e-6 || x < -1e-6) { + final double xpa = 1 + x; + final double xpb = -(xpa - 1 - x); + + final 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 + final double fx1 = xpb / xpa; + final double epsilon = 0.5 * fx1 + 1; + return epsilon * fx1 + hiPrec[1] + hiPrec[0]; + } else { + // Value is small |x| < 1e6, do a Taylor series centered on 1. + final double y = (x * F_1_3 - F_1_2) * x + 1; + return y * x; + } + } + + /** + * 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; + } + + /** + * Computes the <a href="http://mathworld.wolfram.com/Logarithm.html">logarithm</a> in a given + * base. + * + * <p>Returns {@code NaN} if either argument is negative. If {@code base} is 0 and {@code x} is + * positive, 0 is returned. If {@code base} is positive and {@code x} is 0, {@code + * Double.NEGATIVE_INFINITY} is returned. If both arguments are 0, the result is {@code NaN}. + * + * @param base Base of the logarithm, must be greater than 0. + * @param x Argument, must be greater than 0. + * @return the value of the logarithm, i.e. the number {@code y} such that <code> + * base<sup>y</sup> = x</code>. + * @since 1.2 (previously in {@code MathUtils}, moved as of version 3.0) + */ + public static double log(double base, double x) { + return log(x) / log(base); + } + + /** + * Power function. Compute x^y. + * + * @param x a double + * @param y a double + * @return double + */ + public static double pow(final double x, final double y) { + + if (y == 0) { + // y = -0 or y = +0 + return 1.0; + } else { + + final long yBits = Double.doubleToRawLongBits(y); + final int yRawExp = (int) ((yBits & MASK_DOUBLE_EXPONENT) >> 52); + final long yRawMantissa = yBits & MASK_DOUBLE_MANTISSA; + final long xBits = Double.doubleToRawLongBits(x); + final int xRawExp = (int) ((xBits & MASK_DOUBLE_EXPONENT) >> 52); + final long xRawMantissa = xBits & MASK_DOUBLE_MANTISSA; + + if (yRawExp > 1085) { + // y is either a very large integral value that does not fit in a long or it is a + // special number + + if ((yRawExp == 2047 && yRawMantissa != 0) + || (xRawExp == 2047 && xRawMantissa != 0)) { + // NaN + return Double.NaN; + } else if (xRawExp == 1023 && xRawMantissa == 0) { + // x = -1.0 or x = +1.0 + if (yRawExp == 2047) { + // y is infinite + return Double.NaN; + } else { + // y is a large even integer + return 1.0; + } + } else { + // the absolute value of x is either greater or smaller than 1.0 + + // if yRawExp == 2047 and mantissa is 0, y = -infinity or y = +infinity + // if 1085 < yRawExp < 2047, y is simply a large number, however, due to limited + // accuracy, at this magnitude it behaves just like infinity with regards to x + if ((y > 0) ^ (xRawExp < 1023)) { + // either y = +infinity (or large engouh) and abs(x) > 1.0 + // or y = -infinity (or large engouh) and abs(x) < 1.0 + return Double.POSITIVE_INFINITY; + } else { + // either y = +infinity (or large engouh) and abs(x) < 1.0 + // or y = -infinity (or large engouh) and abs(x) > 1.0 + return +0.0; + } + } + + } else { + // y is a regular non-zero number + + if (yRawExp >= 1023) { + // y may be an integral value, which should be handled specifically + final long yFullMantissa = IMPLICIT_HIGH_BIT | yRawMantissa; + if (yRawExp < 1075) { + // normal number with negative shift that may have a fractional part + final long integralMask = (-1L) << (1075 - yRawExp); + if ((yFullMantissa & integralMask) == yFullMantissa) { + // all fractional bits are 0, the number is really integral + final long l = yFullMantissa >> (1075 - yRawExp); + return FastMath.pow(x, (y < 0) ? -l : l); + } + } else { + // normal number with positive shift, always an integral value + // we know it fits in a primitive long because yRawExp > 1085 has been + // handled above + final long l = yFullMantissa << (yRawExp - 1075); + return FastMath.pow(x, (y < 0) ? -l : l); + } + } + + // y is a non-integral value + + if (x == 0) { + // x = -0 or x = +0 + // the integer powers have already been handled above + return y < 0 ? Double.POSITIVE_INFINITY : +0.0; + } else if (xRawExp == 2047) { + if (xRawMantissa == 0) { + // x = -infinity or x = +infinity + return (y < 0) ? +0.0 : Double.POSITIVE_INFINITY; + } else { + // NaN + return Double.NaN; + } + } else if (x < 0) { + // the integer powers have already been handled above + return Double.NaN; + } else { + + // this is the general case, for regular fractional numbers x and y + + // Split y into ya and yb such that y = ya+yb + final double tmp = y * HEX_40000000; + final double ya = (y + tmp) - tmp; + final double yb = y - ya; + + /* Compute ln(x) */ + final double lns[] = new double[2]; + 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 */ + final double tmp1 = lna * HEX_40000000; + final 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 *= lnb; + + final double result = exp(lna, z, null); + // result = result + result * z; + return result; + } + } + } + } + + /** + * Raise a double to an int power. + * + * @param d Number to raise. + * @param e Exponent. + * @return d<sup>e</sup> + * @since 3.1 + */ + public static double pow(double d, int e) { + return pow(d, (long) e); + } + + /** + * Raise a double to a long power. + * + * @param d Number to raise. + * @param e Exponent. + * @return d<sup>e</sup> + * @since 3.6 + */ + public static double pow(double d, long e) { + if (e == 0) { + return 1.0; + } else if (e > 0) { + return new Split(d).pow(e).full; + } else { + return new Split(d).reciprocal().pow(-e).full; + } + } + + /** Class operator on double numbers split into one 26 bits number and one 27 bits number. */ + private static class Split { + + /** Split version of NaN. */ + public static final Split NAN = new Split(Double.NaN, 0); + + /** Split version of positive infinity. */ + public static final Split POSITIVE_INFINITY = new Split(Double.POSITIVE_INFINITY, 0); + + /** Split version of negative infinity. */ + public static final Split NEGATIVE_INFINITY = new Split(Double.NEGATIVE_INFINITY, 0); + + /** Full number. */ + private final double full; + + /** High order bits. */ + private final double high; + + /** Low order bits. */ + private final double low; + + /** + * Simple constructor. + * + * @param x number to split + */ + Split(final double x) { + full = x; + high = Double.longBitsToDouble(Double.doubleToRawLongBits(x) & ((-1L) << 27)); + low = x - high; + } + + /** + * Simple constructor. + * + * @param high high order bits + * @param low low order bits + */ + Split(final double high, final double low) { + this( + high == 0.0 + ? (low == 0.0 + && Double.doubleToRawLongBits(high) + == Long.MIN_VALUE /* negative zero */ + ? -0.0 + : low) + : high + low, + high, + low); + } + + /** + * Simple constructor. + * + * @param full full number + * @param high high order bits + * @param low low order bits + */ + Split(final double full, final double high, final double low) { + this.full = full; + this.high = high; + this.low = low; + } + + /** + * Multiply the instance by another one. + * + * @param b other instance to multiply by + * @return product + */ + public Split multiply(final Split b) { + // beware the following expressions must NOT be simplified, they rely on floating point + // arithmetic properties + final Split mulBasic = new Split(full * b.full); + final double mulError = + low * b.low - (((mulBasic.full - high * b.high) - low * b.high) - high * b.low); + return new Split(mulBasic.high, mulBasic.low + mulError); + } + + /** + * Compute the reciprocal of the instance. + * + * @return reciprocal of the instance + */ + public Split reciprocal() { + + final double approximateInv = 1.0 / full; + final Split splitInv = new Split(approximateInv); + + // if 1.0/d were computed perfectly, remultiplying it by d should give 1.0 + // we want to estimate the error so we can fix the low order bits of approximateInvLow + // beware the following expressions must NOT be simplified, they rely on floating point + // arithmetic properties + final Split product = multiply(splitInv); + final double error = (product.high - 1) + product.low; + + // better accuracy estimate of reciprocal + return Double.isNaN(error) + ? splitInv + : new Split(splitInv.high, splitInv.low - error / full); + } + + /** + * Computes this^e. + * + * @param e exponent (beware, here it MUST be > 0; the only exclusion is Long.MIN_VALUE) + * @return d^e, split in high and low bits + * @since 3.6 + */ + private Split pow(final long e) { + + // prepare result + Split result = new Split(1); + + // d^(2p) + Split d2p = new Split(full, high, low); + + for (long p = e; p != 0; p >>>= 1) { + + if ((p & 0x1) != 0) { + // accurate multiplication result = result * d^(2p) using Veltkamp TwoProduct + // algorithm + result = result.multiply(d2p); + } + + // accurate squaring d^(2(p+1)) = d^(2p) * d^(2p) using Veltkamp TwoProduct + // algorithm + d2p = d2p.multiply(d2p); + } + + if (Double.isNaN(result.full)) { + if (Double.isNaN(full)) { + return Split.NAN; + } else { + // some intermediate numbers exceeded capacity, + // and the low order bits became NaN (because infinity - infinity = NaN) + if (FastMath.abs(full) < 1) { + return new Split(FastMath.copySign(0.0, full), 0.0); + } else if (full < 0 && (e & 0x1) == 1) { + return Split.NEGATIVE_INFINITY; + } else { + return Split.POSITIVE_INFINITY; + } + } + } else { + return result; + } + } + } + + /** + * 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 += d; + + t = costA * sinEpsA; + c = a + t; + d = -(c - a - t); + a = c; + 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 += 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 += d; + + t = costA * sinEpsA; + c = a + t; + d = -(c - a - t); + a = c; + b += d; + + b += sintA * cosEpsB + costA * sinEpsB; + 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 += d; + + t = -sintA * sinEpsA; + c = a + t; + d = -(c - a - t); + a = c; + b += d; + + b += costB * cosEpsA + costA * cosEpsB + costB * cosEpsB; + 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.doubleToRawLongBits(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 += bc << 32; + 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 += (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 += bc << 32; + 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 += (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 += (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 Argument. + * @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.doubleToRawLongBits(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) { + final CodyWaite cw = new CodyWaite(xa); + quadrant = cw.getK() & 3; + xa = cw.getRemA(); + xb = cw.getRemB(); + } + + 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 Argument. + * @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) { + final CodyWaite cw = new CodyWaite(xa); + quadrant = cw.getK() & 3; + xa = cw.getRemA(); + xb = cw.getRemB(); + } + + // 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 Argument. + * @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.doubleToRawLongBits(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) { + final CodyWaite cw = new CodyWaite(xa); + quadrant = cw.getK() & 3; + xa = cw.getRemA(); + xb = cw.getRemB(); + } + + if (xa > 1.5) { + // Accuracy 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) { + if (xa == 0.0) { // Matches +/- 0.0; return correct sign + return leftPlane ? copySign(Math.PI, xa) : xa; + } + + final boolean negate; + if (xa < 0) { + // negative + xa = -xa; + xb = -xb; + negate = true; + } else { + negate = false; + } + + if (xa > 1.633123935319537E16) { // Very large input + return (negate ^ leftPlane) ? (-Math.PI * F_1_2) : (Math.PI * F_1_2); + } + + /* Estimate the closest tabulated arctan value, compute eps = xa-tangentTable */ + final int idx; + if (xa < 1) { + idx = (int) (((-1.7168146928204136 * xa * xa + 8.0) * xa) + 0.5); + } else { + final double oneOverXa = 1 / xa; + idx = + (int) + (-((-1.7168146928204136 * oneOverXa * oneOverXa + 8.0) * oneOverXa) + + 13.07); + } + + final double ttA = TANGENT_TABLE_A[idx]; + final double ttB = TANGENT_TABLE_B[idx]; + + double epsA = xa - ttA; + double epsB = -(epsA - xa + ttA); + epsB += xb - ttB; + + 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]); + final double denom = 1d / (1d + (xa + xb) * (ttA + ttB)); + // double denom = 1.0 / (1.0 + xa*tangentTableA[idx]); + ya = epsA * denom; + yb = epsB * denom; + } else { + double temp2 = xa * ttA; + double za = 1d + temp2; + double zb = -(za - 1d - temp2); + temp2 = xb * ttA + xa * ttB; + temp = za + temp2; + zb += -(temp - za - temp2); + za = temp; + + zb += xb * ttB; + 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 */ + final 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 / (1d + epsA * epsA); + + final double eighths = EIGHTHS[idx]; + + // result = yb + eighths[idx] + ya; + double za = eighths + ya; + double zb = -(za - eighths - ya); + temp = za + yb; + zb += -(temp - za - yb); + za = temp; + + double result = za + zb; + + if (leftPlane) { + // Result is in the left plane + final double resultb = -(result - za - zb); + final double pia = 1.5707963267948966 * 2; + final double pib = 6.123233995736766E-17 * 2; + + za = pia - result; + zb = -(za - pia + result); + zb += pib - 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) { + final double result = x * y; + final double invx = 1d / x; + final double invy = 1d / y; + + if (invx == 0) { // X is infinite + if (x > 0) { + return y; // return +/- 0.0 + } else { + return copySign(Math.PI, y); + } + } + + if (x < 0 || invx < 0) { + if (y < 0 || invy < 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 * F_1_4; + } + + if (x == Double.NEGATIVE_INFINITY) { + return Math.PI * F_3_4; + } + + return Math.PI * F_1_2; + } + + if (y == Double.NEGATIVE_INFINITY) { + if (x == Double.POSITIVE_INFINITY) { + return -Math.PI * F_1_4; + } + + if (x == Double.NEGATIVE_INFINITY) { + return -Math.PI * F_3_4; + } + + return -Math.PI * F_1_2; + } + + if (x == Double.POSITIVE_INFINITY) { + if (y > 0 || 1 / y > 0) { + return 0d; + } + + if (y < 0 || 1 / y < 0) { + return -0d; + } + } + + if (x == Double.NEGATIVE_INFINITY) { + if (y > 0.0 || 1 / y > 0.0) { + return Math.PI; + } + + if (y < 0 || 1 / y < 0) { + return -Math.PI; + } + } + + // Neither y nor x can be infinite or NAN here + + if (x == 0) { + if (y > 0 || 1 / y > 0) { + return Math.PI * F_1_2; + } + + if (y < 0 || 1 / y < 0) { + return -Math.PI * F_1_2; + } + } + + // 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; + + final double temp = ra + rb; + rb = -(temp - ra - rb); + ra = temp; + + if (ra == 0) { // Fix up the sign so atan works correctly + ra = copySign(0d, y); + } + + // Call atan + final 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.doubleToRawLongBits(x); + int exponent = (int) ((inbits >> 52) & 0x7ff) - 1023; + boolean subnormal = false; + + if (exponent == -1023) { + if (x == 0) { + return x; + } + + /* Subnormal, so normalize */ + subnormal = true; + x *= 1.8014398509481984E16; // 2^54 + inbits = Double.doubleToRawLongBits(x); + exponent = (int) ((inbits >> 52) & 0x7ff) - 1023; + } + + if (exponent == 1024) { + // Nan or infinity. Don't care which. + return x; + } + + /* Divide the exponent by 3 */ + int exp3 = exponent / 3; + + /* p2 will be the nearest power of 2 to x with its exponent divided by 3 */ + double p2 = + Double.longBitsToDouble( + (inbits & 0x8000000000000000L) | (long) (((exp3 + 1023) & 0x7ff)) << 52); + + /* This will be a number between 1 and 2 */ + final double mant = + Double.longBitsToDouble((inbits & 0x000fffffffffffffL) | 0x3ff0000000000000L); + + /* Estimate the cube root of mant by polynomial */ + double est = -0.010714690733195933; + est = est * mant + 0.0875862700108075; + est = est * mant + -0.3058015757857271; + est = est * mant + 0.7249995199969751; + est = est * mant + 0.5039018405998233; + + est *= CBRTTWO[exponent % 3 + 2]; + + // est should now be good to about 15 bits of precision. Do 2 rounds of + // Newton's method to get closer, this should get us full double precision + // Scale down x for the purpose of doing newtons method. This avoids over/under flows. + final double xs = x / (p2 * p2 * p2); + est += (xs - est * est * est) / (3 * est * est); + est += (xs - est * est * est) / (3 * est * est); + + // Do one round of Newton's method in extended precision to get the last bit right. + double temp = est * HEX_40000000; + double ya = est + temp - temp; + double yb = est - ya; + + double za = ya * ya; + double zb = ya * yb * 2.0 + yb * yb; + temp = za * HEX_40000000; + double temp2 = za + temp - temp; + zb += za - temp2; + za = temp2; + + zb = za * yb + ya * zb + zb * yb; + za *= 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 *= 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) { + final int i = x >>> 31; + return (x ^ (~i + 1)) + i; + } + + /** + * Absolute value. + * + * @param x number from which absolute value is requested + * @return abs(x) + */ + public static long abs(final long x) { + final long l = x >>> 63; + // l is one if x negative zero else + // ~l+1 is zero if x is positive, -1 if x is negative + // x^(~l+1) is x is x is positive, ~x if x is negative + // add around + return (x ^ (~l + 1)) + l; + } + + /** + * Absolute value. + * + * @param x number from which absolute value is requested + * @return abs(x) + */ + public static float abs(final float x) { + return Float.intBitsToFloat(MASK_NON_SIGN_INT & Float.floatToRawIntBits(x)); + } + + /** + * Absolute value. + * + * @param x number from which absolute value is requested + * @return abs(x) + */ + public static double abs(double x) { + return Double.longBitsToDouble(MASK_NON_SIGN_LONG & Double.doubleToRawLongBits(x)); + } + + /** + * 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.doubleToRawLongBits(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.doubleToRawLongBits(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 |= 1L << 52; + + // scales down complete mantissa, hence losing least significant bits + final long mostSignificantLostBit = mantissa & (1L << (-scaledExponent)); + 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 <<= 1; + --scaledExponent; + } + ++scaledExponent; + 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 |= 1 << 23; + + // scales down complete mantissa, hence losing least significant bits + final int mostSignificantLostBit = mantissa & (1 << (-scaledExponent)); + 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 <<= 1; + --scaledExponent; + } + ++scaledExponent; + 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>-MAX_VALUE + * <li>-MIN_VALUE + * <li>-0.0 + * <li>+0.0 + * <li>+MIN_VALUE + * <li>+MAX_VALUE + * <li>+INFINITY + * <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>If {@code d} is infinite and direction does not bring it back to finite numbers, it + * is returned unchanged. + * + * @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 + // can use raw bits since already dealt with infinity and NaN + final long bits = Double.doubleToRawLongBits(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>-MAX_VALUE + * <li>-MIN_VALUE + * <li>-0.0 + * <li>+0.0 + * <li>+MIN_VALUE + * <li>+MAX_VALUE + * <li>+INFINITY + * <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>If {@code f} is infinite and direction does not bring it back to finite numbers, it + * is returned unchanged. + * + * @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>else, if either argument is NaN then the result is NaN. + * </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>If the result is not NaN, the sign of the result equals the sign of the dividend. + * <li>If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN. + * <li>If the dividend is finite and the divisor is an infinity, the result equals the + * dividend. + * <li>If the dividend is a zero and the divisor is finite, the result equals the dividend. + * </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 + } + + /** + * Convert a long to interger, detecting overflows + * + * @param n number to convert to int + * @return integer with same valie as n if no overflows occur + * @exception MathArithmeticException if n cannot fit into an int + * @since 3.4 + */ + public static int toIntExact(final long n) throws MathArithmeticException { + if (n < Integer.MIN_VALUE || n > Integer.MAX_VALUE) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW); + } + return (int) n; + } + + /** + * Increment a number, detecting overflows. + * + * @param n number to increment + * @return n+1 if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static int incrementExact(final int n) throws MathArithmeticException { + + if (n == Integer.MAX_VALUE) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_ADDITION, n, 1); + } + + return n + 1; + } + + /** + * Increment a number, detecting overflows. + * + * @param n number to increment + * @return n+1 if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static long incrementExact(final long n) throws MathArithmeticException { + + if (n == Long.MAX_VALUE) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_ADDITION, n, 1); + } + + return n + 1; + } + + /** + * Decrement a number, detecting overflows. + * + * @param n number to decrement + * @return n-1 if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static int decrementExact(final int n) throws MathArithmeticException { + + if (n == Integer.MIN_VALUE) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_SUBTRACTION, n, 1); + } + + return n - 1; + } + + /** + * Decrement a number, detecting overflows. + * + * @param n number to decrement + * @return n-1 if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static long decrementExact(final long n) throws MathArithmeticException { + + if (n == Long.MIN_VALUE) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_SUBTRACTION, n, 1); + } + + return n - 1; + } + + /** + * Add two numbers, detecting overflows. + * + * @param a first number to add + * @param b second number to add + * @return a+b if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static int addExact(final int a, final int b) throws MathArithmeticException { + + // compute sum + final int sum = a + b; + + // check for overflow + if ((a ^ b) >= 0 && (sum ^ b) < 0) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_ADDITION, a, b); + } + + return sum; + } + + /** + * Add two numbers, detecting overflows. + * + * @param a first number to add + * @param b second number to add + * @return a+b if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static long addExact(final long a, final long b) throws MathArithmeticException { + + // compute sum + final long sum = a + b; + + // check for overflow + if ((a ^ b) >= 0 && (sum ^ b) < 0) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_ADDITION, a, b); + } + + return sum; + } + + /** + * Subtract two numbers, detecting overflows. + * + * @param a first number + * @param b second number to subtract from a + * @return a-b if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static int subtractExact(final int a, final int b) { + + // compute subtraction + final int sub = a - b; + + // check for overflow + if ((a ^ b) < 0 && (sub ^ b) >= 0) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_SUBTRACTION, a, b); + } + + return sub; + } + + /** + * Subtract two numbers, detecting overflows. + * + * @param a first number + * @param b second number to subtract from a + * @return a-b if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static long subtractExact(final long a, final long b) { + + // compute subtraction + final long sub = a - b; + + // check for overflow + if ((a ^ b) < 0 && (sub ^ b) >= 0) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_SUBTRACTION, a, b); + } + + return sub; + } + + /** + * Multiply two numbers, detecting overflows. + * + * @param a first number to multiply + * @param b second number to multiply + * @return a*b if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static int multiplyExact(final int a, final int b) { + if (((b > 0) && (a > Integer.MAX_VALUE / b || a < Integer.MIN_VALUE / b)) + || ((b < -1) && (a > Integer.MIN_VALUE / b || a < Integer.MAX_VALUE / b)) + || ((b == -1) && (a == Integer.MIN_VALUE))) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_MULTIPLICATION, a, b); + } + return a * b; + } + + /** + * Multiply two numbers, detecting overflows. + * + * @param a first number to multiply + * @param b second number to multiply + * @return a*b if no overflows occur + * @exception MathArithmeticException if an overflow occurs + * @since 3.4 + */ + public static long multiplyExact(final long a, final long b) { + if (((b > 0l) && (a > Long.MAX_VALUE / b || a < Long.MIN_VALUE / b)) + || ((b < -1l) && (a > Long.MIN_VALUE / b || a < Long.MAX_VALUE / b)) + || ((b == -1l) && (a == Long.MIN_VALUE))) { + throw new MathArithmeticException(LocalizedFormats.OVERFLOW_IN_MULTIPLICATION, a, b); + } + return a * b; + } + + /** + * Finds q such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0. + * + * <p>This methods returns the same value as integer division when a and b are same signs, but + * returns a different value when they are opposite (i.e. q is negative). + * + * @param a dividend + * @param b divisor + * @return q such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0 + * @exception MathArithmeticException if b == 0 + * @see #floorMod(int, int) + * @since 3.4 + */ + public static int floorDiv(final int a, final int b) throws MathArithmeticException { + + if (b == 0) { + throw new MathArithmeticException(LocalizedFormats.ZERO_DENOMINATOR); + } + + final int m = a % b; + if ((a ^ b) >= 0 || m == 0) { + // a an b have same sign, or division is exact + return a / b; + } else { + // a and b have opposite signs and division is not exact + return (a / b) - 1; + } + } + + /** + * Finds q such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0. + * + * <p>This methods returns the same value as integer division when a and b are same signs, but + * returns a different value when they are opposite (i.e. q is negative). + * + * @param a dividend + * @param b divisor + * @return q such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0 + * @exception MathArithmeticException if b == 0 + * @see #floorMod(long, long) + * @since 3.4 + */ + public static long floorDiv(final long a, final long b) throws MathArithmeticException { + + if (b == 0l) { + throw new MathArithmeticException(LocalizedFormats.ZERO_DENOMINATOR); + } + + final long m = a % b; + if ((a ^ b) >= 0l || m == 0l) { + // a an b have same sign, or division is exact + return a / b; + } else { + // a and b have opposite signs and division is not exact + return (a / b) - 1l; + } + } + + /** + * Finds r such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0. + * + * <p>This methods returns the same value as integer modulo when a and b are same signs, but + * returns a different value when they are opposite (i.e. q is negative). + * + * @param a dividend + * @param b divisor + * @return r such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0 + * @exception MathArithmeticException if b == 0 + * @see #floorDiv(int, int) + * @since 3.4 + */ + public static int floorMod(final int a, final int b) throws MathArithmeticException { + + if (b == 0) { + throw new MathArithmeticException(LocalizedFormats.ZERO_DENOMINATOR); + } + + final int m = a % b; + if ((a ^ b) >= 0 || m == 0) { + // a an b have same sign, or division is exact + return m; + } else { + // a and b have opposite signs and division is not exact + return b + m; + } + } + + /** + * Finds r such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0. + * + * <p>This methods returns the same value as integer modulo when a and b are same signs, but + * returns a different value when they are opposite (i.e. q is negative). + * + * @param a dividend + * @param b divisor + * @return r such that a = q b + r with 0 <= r < b if b > 0 and b < r <= 0 if b < 0 + * @exception MathArithmeticException if b == 0 + * @see #floorDiv(long, long) + * @since 3.4 + */ + public static long floorMod(final long a, final long b) { + + if (b == 0l) { + throw new MathArithmeticException(LocalizedFormats.ZERO_DENOMINATOR); + } + + final long m = a % b; + if ((a ^ b) >= 0l || m == 0l) { + // a an b have same sign, or division is exact + return m; + } else { + // a and b have opposite signs and division is not exact + return b + m; + } + } + + /** + * 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) { + // The highest order bit is going to be zero if the + // highest order bit of m and s is the same and one otherwise. + // So (m^s) will be positive if both m and s have the same sign + // and negative otherwise. + final long m = Double.doubleToRawLongBits(magnitude); // don't care about NaN + final long s = Double.doubleToRawLongBits(sign); + if ((m ^ s) >= 0) { + 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) { + // The highest order bit is going to be zero if the + // highest order bit of m and s is the same and one otherwise. + // So (m^s) will be positive if both m and s have the same sign + // and negative otherwise. + final int m = Float.floatToRawIntBits(magnitude); + final int s = Float.floatToRawIntBits(sign); + if ((m ^ s) >= 0) { + 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. + * + * @param d number from which exponent is requested + * @return exponent for d in IEEE754 representation, without bias + */ + public static int getExponent(final double d) { + // NaN and Infinite will return 1024 anywho so can use raw bits + return (int) ((Double.doubleToRawLongBits(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. + * + * @param f number from which exponent is requested + * @return exponent for d in IEEE754 representation, without bias + */ + public static int getExponent(final float f) { + // NaN and Infinite will return the same exponent anywho so can use raw bits + return ((Float.floatToRawIntBits(f) >>> 23) & 0xff) - 127; + } + + /** + * Print out contents of arrays, and check the length. + * + * <p>used to generate the preset arrays originally. + * + * @param a unused + */ + public static void main(String[] a) { + PrintStream out = System.out; + FastMathCalc.printarray( + out, "EXP_INT_TABLE_A", EXP_INT_TABLE_LEN, ExpIntTable.EXP_INT_TABLE_A); + FastMathCalc.printarray( + out, "EXP_INT_TABLE_B", EXP_INT_TABLE_LEN, ExpIntTable.EXP_INT_TABLE_B); + FastMathCalc.printarray( + out, "EXP_FRAC_TABLE_A", EXP_FRAC_TABLE_LEN, ExpFracTable.EXP_FRAC_TABLE_A); + FastMathCalc.printarray( + out, "EXP_FRAC_TABLE_B", EXP_FRAC_TABLE_LEN, ExpFracTable.EXP_FRAC_TABLE_B); + FastMathCalc.printarray(out, "LN_MANT", LN_MANT_LEN, lnMant.LN_MANT); + FastMathCalc.printarray(out, "SINE_TABLE_A", SINE_TABLE_LEN, SINE_TABLE_A); + FastMathCalc.printarray(out, "SINE_TABLE_B", SINE_TABLE_LEN, SINE_TABLE_B); + FastMathCalc.printarray(out, "COSINE_TABLE_A", SINE_TABLE_LEN, COSINE_TABLE_A); + FastMathCalc.printarray(out, "COSINE_TABLE_B", SINE_TABLE_LEN, COSINE_TABLE_B); + FastMathCalc.printarray(out, "TANGENT_TABLE_A", SINE_TABLE_LEN, TANGENT_TABLE_A); + FastMathCalc.printarray(out, "TANGENT_TABLE_B", SINE_TABLE_LEN, TANGENT_TABLE_B); + } + + /** Enclose large data table in nested static class so it's only loaded on first access. */ + private static class ExpIntTable { + /** + * Exponential evaluated at integer values, exp(x) = expIntTableA[x + + * EXP_INT_TABLE_MAX_INDEX] + expIntTableB[x+EXP_INT_TABLE_MAX_INDEX]. + */ + private static final double[] EXP_INT_TABLE_A; + + /** + * Exponential evaluated at integer values, exp(x) = expIntTableA[x + + * EXP_INT_TABLE_MAX_INDEX] + expIntTableB[x+EXP_INT_TABLE_MAX_INDEX] + */ + private static final double[] EXP_INT_TABLE_B; + + static { + if (RECOMPUTE_TABLES_AT_RUNTIME) { + EXP_INT_TABLE_A = new double[FastMath.EXP_INT_TABLE_LEN]; + EXP_INT_TABLE_B = new double[FastMath.EXP_INT_TABLE_LEN]; + + final double tmp[] = new double[2]; + final double recip[] = new double[2]; + + // Populate expIntTable + for (int i = 0; i < FastMath.EXP_INT_TABLE_MAX_INDEX; i++) { + FastMathCalc.expint(i, tmp); + EXP_INT_TABLE_A[i + FastMath.EXP_INT_TABLE_MAX_INDEX] = tmp[0]; + EXP_INT_TABLE_B[i + FastMath.EXP_INT_TABLE_MAX_INDEX] = tmp[1]; + + if (i != 0) { + // Negative integer powers + FastMathCalc.splitReciprocal(tmp, recip); + EXP_INT_TABLE_A[FastMath.EXP_INT_TABLE_MAX_INDEX - i] = recip[0]; + EXP_INT_TABLE_B[FastMath.EXP_INT_TABLE_MAX_INDEX - i] = recip[1]; + } + } + } else { + EXP_INT_TABLE_A = FastMathLiteralArrays.loadExpIntA(); + EXP_INT_TABLE_B = FastMathLiteralArrays.loadExpIntB(); + } + } + } + + /** Enclose large data table in nested static class so it's only loaded on first access. */ + private static class ExpFracTable { + /** + * Exponential over the range of 0 - 1 in increments of 2^-10 exp(x/1024) = expFracTableA[x] + * + expFracTableB[x]. 1024 = 2^10 + */ + private static final double[] EXP_FRAC_TABLE_A; + + /** + * Exponential over the range of 0 - 1 in increments of 2^-10 exp(x/1024) = expFracTableA[x] + * + expFracTableB[x]. + */ + private static final double[] EXP_FRAC_TABLE_B; + + static { + if (RECOMPUTE_TABLES_AT_RUNTIME) { + EXP_FRAC_TABLE_A = new double[FastMath.EXP_FRAC_TABLE_LEN]; + EXP_FRAC_TABLE_B = new double[FastMath.EXP_FRAC_TABLE_LEN]; + + final double tmp[] = new double[2]; + + // Populate expFracTable + final double factor = 1d / (EXP_FRAC_TABLE_LEN - 1); + for (int i = 0; i < EXP_FRAC_TABLE_A.length; i++) { + FastMathCalc.slowexp(i * factor, tmp); + EXP_FRAC_TABLE_A[i] = tmp[0]; + EXP_FRAC_TABLE_B[i] = tmp[1]; + } + } else { + EXP_FRAC_TABLE_A = FastMathLiteralArrays.loadExpFracA(); + EXP_FRAC_TABLE_B = FastMathLiteralArrays.loadExpFracB(); + } + } + } + + /** Enclose large data table in nested static class so it's only loaded on first access. */ + private static class lnMant { + /** Extended precision logarithm table over the range 1 - 2 in increments of 2^-10. */ + private static final double[][] LN_MANT; + + static { + if (RECOMPUTE_TABLES_AT_RUNTIME) { + LN_MANT = new double[FastMath.LN_MANT_LEN][]; + + // Populate lnMant table + for (int i = 0; i < LN_MANT.length; i++) { + final double d = + Double.longBitsToDouble((((long) i) << 42) | 0x3ff0000000000000L); + LN_MANT[i] = FastMathCalc.slowLog(d); + } + } else { + LN_MANT = FastMathLiteralArrays.loadLnMant(); + } + } + } + + /** Enclose the Cody/Waite reduction (used in "sin", "cos" and "tan"). */ + private static class CodyWaite { + /** k */ + private final int finalK; + + /** remA */ + private final double finalRemA; + + /** remB */ + private final double finalRemB; + + /** + * @param xa Argument. + */ + CodyWaite(double xa) { + // 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) { + 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; + } + + this.finalK = k; + this.finalRemA = remA; + this.finalRemB = remB; + } + + /** + * @return k + */ + int getK() { + return finalK; + } + + /** + * @return remA + */ + double getRemA() { + return finalRemA; + } + + /** + * @return remB + */ + double getRemB() { + return finalRemB; + } + } +} |