hoosiertransfer-mod/src/main/java/net/jafama/CmnFastMath.java

2135 lines
80 KiB
Java

/*
* Copyright 2014-2015 Jeff Hain
*
* Licensed 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.
*/
/*
* =============================================================================
* Notice of fdlibm package this program is partially derived from:
*
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* =============================================================================
*/
package net.jafama;
/**
* Stuffs for FastMath and StrictFastMath.
*/
abstract class CmnFastMath {
/*
* For trigonometric functions, use of look-up tables and Taylor-Lagrange formula
* with 4 derivatives (more take longer to compute and don't add much accuracy,
* less require larger tables (which use more memory, take more time to initialize,
* and are slower to access (at least on the machine they were developed on))).
*
* For angles reduction of cos/sin/tan functions:
* - for small values, instead of reducing angles, and then computing the best index
* for look-up tables, we compute this index right away, and use it for reduction,
* - for large values, treatments derived from fdlibm package are used, as done in
* java.lang.Math. They are faster but still "slow", so if you work with
* large numbers and need speed over accuracy for them, you might want to use
* normalizeXXXFast treatments before your function, or modify cos/sin/tan
* so that they call the fast normalization treatments instead of the accurate ones.
* NB: If an angle is huge (like PI*1e20), in double precision format its last digits
* are zeros, which most likely is not the case for the intended value, and doing
* an accurate reduction on a very inaccurate value is most likely pointless.
* But it gives some sort of coherence that could be needed in some cases.
*
* Multiplication on double appears to be about as fast (or not much slower) than call
* to <double_array>[<index>], and regrouping some doubles in a private class, to use
* index only once, does not seem to speed things up, so:
* - for uniformly tabulated values, to retrieve the parameter corresponding to
* an index, we recompute it rather than using an array to store it,
* - for cos/sin, we recompute derivatives divided by (multiplied by inverse of)
* factorial each time, rather than storing them in arrays.
*
* Lengths of look-up tables are usually of the form 2^n+1, for their values to be
* of the form (<a_constant> * k/2^n, k in 0 .. 2^n), so that particular values
* (PI/2, etc.) are "exactly" computed, as well as for other reasons.
*
* Tables are put in specific inner classes, to be lazily initialized.
* Always doing strict tables initialization, even if StrictFastMath delegates
* to StrictMath and doesn't use tables, which makes tables initialization a bit
* slower but code simpler.
* Using redefined pure Java treatments during tables initialization,
* instead of Math or StrictMath ones (even asin(double)), can be very slow,
* because class loading is likely not to be optimized.
*
* Most math treatments I could find on the web, including "fast" ones,
* usually take care of special cases (NaN, etc.) at the beginning, and
* then deal with the general case, which adds a useless overhead for the
* general (and common) case. In this class, special cases are only dealt
* with when needed, and if the general case does not already handle them.
*/
/*
* Regarding strictfp-ness:
*
* Switching from/to strictfp has some overhead, so we try to only
* strictfp-ize when needed (or when clueless).
* Compile-time constants are computed in a FP-strict way, so no need
* to make this whole class strictfp.
*/
//--------------------------------------------------------------------------
// CONFIGURATION
//--------------------------------------------------------------------------
/*
* FastMath
*/
static final boolean FM_USE_JDK_MATH = getBooleanProperty("jafama.usejdk", false);
/**
* Used for both FastMath.log(double) and FastMath.log10(double).
*/
static final boolean FM_USE_REDEFINED_LOG = getBooleanProperty("jafama.fastlog", false);
static final boolean FM_USE_REDEFINED_SQRT = getBooleanProperty("jafama.fastsqrt", false);
/**
* Set it to true if FastMath.sqrt(double) is slow
* (more tables, but less calls to FastMath.sqrt(double)).
*/
static final boolean FM_USE_POWTABS_FOR_ASIN = false;
/*
* StrictFastMath
*/
static final boolean SFM_USE_JDK_MATH = getBooleanProperty("jafama.strict.usejdk", false);
/**
* Used for both StrictFastMath.log(double) and StrictFastMath.log10(double).
* True by default because the StrictMath implementations can be slow.
*/
static final boolean SFM_USE_REDEFINED_LOG = getBooleanProperty("jafama.strict.fastlog", true);
static final boolean SFM_USE_REDEFINED_SQRT = getBooleanProperty("jafama.strict.fastsqrt", false);
/**
* Set it to true if StrictFastMath.sqrt(double) is slow
* (more tables, but less calls to StrictFastMath.sqrt(double)).
*/
static final boolean SFM_USE_POWTABS_FOR_ASIN = false;
/*
* Common to FastMath and StrictFastMath.
*/
/**
* Using two pow tab can just make things barely faster,
* and could relatively hurt in case of cache-misses,
* especially for methods that otherwise wouldn't rely
* on any tab, so we don't use it.
*/
static final boolean USE_TWO_POW_TAB = false;
/**
* Because on some architectures, some casts can be slow,
* especially for large values.
* Might make things a bit slower for latest architectures,
* but not as much as it makes them faster for older ones.
*/
static final boolean ANTI_SLOW_CASTS = true;
/**
* If some methods get JIT-optimized, they might crash
* if they contain "(var == xxx)" with var being NaN
* (can happen with Java 6u29).
*
* The crash does not happen if we replace "==" with "<" or ">".
*
* Only the code that has been observed to trigger the bug
* has been modified.
*/
static final boolean ANTI_JIT_OPTIM_CRASH_ON_NAN = true;
//--------------------------------------------------------------------------
// GENERAL CONSTANTS
//--------------------------------------------------------------------------
/**
* Closest double approximation of e.
*/
public static final double E = Math.E;
/**
* Closest double approximation of pi, which is inferior to mathematical pi:
* pi ~= 3.14159265358979323846...
* PI ~= 3.141592653589793
*/
public static final double PI = Math.PI;
/**
* High double approximation of pi, which is further from pi
* than the low approximation PI:
* pi ~= 3.14159265358979323846...
* PI ~= 3.141592653589793
* PI_SUP ~= 3.1415926535897936
*/
public static final double PI_SUP = Double.longBitsToDouble(Double.doubleToRawLongBits(Math.PI)+1);
static final double ONE_DIV_F2 = 1/2.0;
static final double ONE_DIV_F3 = 1/6.0;
static final double ONE_DIV_F4 = 1/24.0;
static final float TWO_POW_23_F = (float)NumbersUtils.twoPow(23);
static final double TWO_POW_24 = NumbersUtils.twoPow(24);
private static final double TWO_POW_N24 = NumbersUtils.twoPow(-24);
static final double TWO_POW_26 = NumbersUtils.twoPow(26);
static final double TWO_POW_N26 = NumbersUtils.twoPow(-26);
// First double value (from zero) such as (value+-1/value == value).
static final double TWO_POW_27 = NumbersUtils.twoPow(27);
static final double TWO_POW_N27 = NumbersUtils.twoPow(-27);
static final double TWO_POW_N28 = NumbersUtils.twoPow(-28);
static final double TWO_POW_52 = NumbersUtils.twoPow(52);
static final double TWO_POW_N55 = NumbersUtils.twoPow(-55);
static final double TWO_POW_66 = NumbersUtils.twoPow(66);
static final double TWO_POW_512 = NumbersUtils.twoPow(512);
static final double TWO_POW_N512 = NumbersUtils.twoPow(-512);
/**
* Double.MIN_NORMAL since Java 6.
*/
static final double DOUBLE_MIN_NORMAL = Double.longBitsToDouble(0x0010000000000000L); // 2.2250738585072014E-308
// Not storing float/double mantissa size in constants,
// for 23 and 52 are shorter to read and more
// bitwise-explicit than some constant's name.
static final int MIN_DOUBLE_EXPONENT = -1074;
static final int MIN_DOUBLE_NORMAL_EXPONENT = -1022;
static final int MAX_DOUBLE_EXPONENT = 1023;
static final int MIN_FLOAT_NORMAL_EXPONENT = -126;
static final int MAX_FLOAT_EXPONENT = 127;
private static final double SQRT_2 = StrictMath.sqrt(2.0);
static final double LOG_2 = StrictMath.log(2.0);
static final double LOG_TWO_POW_27 = StrictMath.log(TWO_POW_27);
static final double LOG_DOUBLE_MAX_VALUE = StrictMath.log(Double.MAX_VALUE);
static final double INV_LOG_10 = 1.0/StrictMath.log(10.0);
static final double DOUBLE_BEFORE_60 = Double.longBitsToDouble(Double.doubleToRawLongBits(60.0)-1);
//--------------------------------------------------------------------------
// CONSTANTS FOR NORMALIZATIONS
//--------------------------------------------------------------------------
/**
* Table of constants for 1/(PI/2), 282 Hex digits (enough for normalizing doubles).
* 1/(PI/2) approximation = sum of TWO_OVER_PI_TAB[i]*2^(-24*(i+1)).
*
* double and not int, to avoid int-to-double cast during computations.
*/
private static final double TWO_OVER_PI_TAB[] = {
0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
0x424DD2, 0xe00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
0x3991d6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B};
/*
* Constants for PI/2. Only the 23 most significant bits of each mantissa are used.
* 2*PI approximation = sum of TWOPI_TAB<i>.
*/
private static final double PIO2_TAB0 = Double.longBitsToDouble(0x3FF921FB40000000L);
private static final double PIO2_TAB1 = Double.longBitsToDouble(0x3E74442D00000000L);
private static final double PIO2_TAB2 = Double.longBitsToDouble(0x3CF8469880000000L);
private static final double PIO2_TAB3 = Double.longBitsToDouble(0x3B78CC5160000000L);
private static final double PIO2_TAB4 = Double.longBitsToDouble(0x39F01B8380000000L);
private static final double PIO2_TAB5 = Double.longBitsToDouble(0x387A252040000000L);
static final double PIO2_INV = Double.longBitsToDouble(0x3FE45F306DC9C883L); // 6.36619772367581382433e-01 53 bits of 2/pi
static final double PIO2_HI = Double.longBitsToDouble(0x3FF921FB54400000L); // 1.57079632673412561417e+00 first 33 bits of pi/2
static final double PIO2_LO = Double.longBitsToDouble(0x3DD0B4611A626331L); // 6.07710050650619224932e-11 pi/2 - PIO2_HI
static final double PI_INV = PIO2_INV/2;
static final double PI_HI = 2*PIO2_HI;
static final double PI_LO = 2*PIO2_LO;
static final double TWOPI_INV = PIO2_INV/4;
static final double TWOPI_HI = 4*PIO2_HI;
static final double TWOPI_LO = 4*PIO2_LO;
/**
* Bit = 0 where quadrant is encoded in remainder bits.
*/
private static final long QUADRANT_BITS_0_MASK = 0xCFFFFFFFFFFFFFFFL;
/**
* Remainder bits where quadrant is encoded, 0 elsewhere.
*/
private static final long QUADRANT_PLACE_BITS = 0x3000000000000000L;
/**
* fdlibm uses 2^19*PI/2 here.
* With 2^18*PI/2 we would be more accurate, for example when normalizing
* 822245.903631403, which is close to 2^19*PI/2, but we are still in
* our accuracy tolerance with fdlibm's value (but not 2^20*PI/2) so we
* stick to it, to help being faster than (Strict)Math for values in
* [2^18*PI/2,2^19*PI/2].
*
* For tests, can use a smaller value, for heavy remainder
* not to only be used with huge values.
*/
static final double NORMALIZE_ANGLE_MAX_MEDIUM_DOUBLE_PIO2 = StrictMath.pow(2.0,19.0)*(Math.PI/2);
/**
* 2*Math.PI, normalized into [-PI,PI], as returned by
* StrictMath.asin(StrictMath.sin(2*Math.PI))
* (asin behaves as identity for this).
*
* NB: NumbersUtils.minus2PI(2*Math.PI) returns -2.449293598153844E-16,
* which is different due to not using an accurate enough definition of PI.
*/
static final double TWO_MATH_PI_IN_MINUS_PI_PI = -2.4492935982947064E-16;
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR SIN AND COS
//--------------------------------------------------------------------------
static final int SIN_COS_TABS_SIZE = (1<<getTabSizePower(11)) + 1;
static final double SIN_COS_DELTA_HI = TWOPI_HI/(SIN_COS_TABS_SIZE-1);
static final double SIN_COS_DELTA_LO = TWOPI_LO/(SIN_COS_TABS_SIZE-1);
static final double SIN_COS_INDEXER = 1/(SIN_COS_DELTA_HI+SIN_COS_DELTA_LO);
static final class MyTSinCos {
static final double[] sinTab = new double[SIN_COS_TABS_SIZE];
static final double[] cosTab = new double[SIN_COS_TABS_SIZE];
static {
init();
}
private static strictfp void init() {
final int SIN_COS_PI_INDEX = (SIN_COS_TABS_SIZE-1)/2;
final int SIN_COS_PI_MUL_2_INDEX = 2*SIN_COS_PI_INDEX;
final int SIN_COS_PI_MUL_0_5_INDEX = SIN_COS_PI_INDEX/2;
final int SIN_COS_PI_MUL_1_5_INDEX = 3*SIN_COS_PI_INDEX/2;
for (int i=0;i<SIN_COS_TABS_SIZE;i++) {
// angle: in [0,2*PI] (doesn't seem to help to have it in [-PI,PI]).
double angle = i * SIN_COS_DELTA_HI + i * SIN_COS_DELTA_LO;
double sinAngle = StrictMath.sin(angle);
double cosAngle = StrictMath.cos(angle);
// For indexes corresponding to zero cosine or sine, we make sure
// the value is zero and not an epsilon, since each value
// corresponds to sin-or-cos(i*PI/n), where PI is a more accurate
// definition of PI than Math.PI.
// This allows for a much better accuracy for results close to zero.
if (i == SIN_COS_PI_INDEX) {
sinAngle = 0.0;
} else if (i == SIN_COS_PI_MUL_2_INDEX) {
sinAngle = 0.0;
} else if (i == SIN_COS_PI_MUL_0_5_INDEX) {
cosAngle = 0.0;
} else if (i == SIN_COS_PI_MUL_1_5_INDEX) {
cosAngle = 0.0;
}
sinTab[i] = sinAngle;
cosTab[i] = cosAngle;
}
}
}
/**
* Max abs value for index-based reduction, above which we use regular angle normalization.
* This value must be < (Integer.MAX_VALUE / SIN_COS_INDEXER), to stay in range of int type.
* If too high, error gets larger because index-based reduction doesn't use an accurate
* enough definition of PI.
* If too low, and if we would be using remainder into [-PI,PI] instead of into [-PI/4,PI/4],
* error would get larger as well, because remainder would just provide a double, while
* index-based reduction is more accurate, using delta from index values and HI/LO values.
*/
static final double SIN_COS_MAX_VALUE_FOR_INT_MODULO = ((Integer.MAX_VALUE>>9) / SIN_COS_INDEXER) * 0.99;
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR TAN
//--------------------------------------------------------------------------
// We use the following formula:
// 1) tan(-x) = -tan(x)
// 2) tan(x) = 1/tan(PI/2-x)
// ---> we only have to compute tan(x) on [0,A] with PI/4<=A<PI/2.
/**
* We use indexing past look-up tables, so that indexing information
* allows for fast recomputation of angle in [0,PI/2] range.
*/
static final int TAN_VIRTUAL_TABS_SIZE = (1<<getTabSizePower(12)) + 1;
/**
* Must be >= 45deg, and supposed to be >= 51.4deg, as fdlibm code is not
* supposed to work with values inferior to that (51.4deg is about
* (PI/2-Double.longBitsToDouble(0x3FE5942800000000L))).
*/
static final double TAN_MAX_VALUE_FOR_TABS = StrictMath.toRadians(77.0);
static final int TAN_TABS_SIZE = (int)((TAN_MAX_VALUE_FOR_TABS/(Math.PI/2)) * (TAN_VIRTUAL_TABS_SIZE-1)) + 1;
static final double TAN_DELTA_HI = PIO2_HI/(TAN_VIRTUAL_TABS_SIZE-1);
static final double TAN_DELTA_LO = PIO2_LO/(TAN_VIRTUAL_TABS_SIZE-1);
static final double TAN_INDEXER = 1/(TAN_DELTA_HI+TAN_DELTA_LO);
static final class MyTTan {
static final double[] tanTab = new double[TAN_TABS_SIZE];
static final double[] tanDer1DivF1Tab = new double[TAN_TABS_SIZE];
static final double[] tanDer2DivF2Tab = new double[TAN_TABS_SIZE];
static final double[] tanDer3DivF3Tab = new double[TAN_TABS_SIZE];
static final double[] tanDer4DivF4Tab = new double[TAN_TABS_SIZE];
static {
init();
}
private static strictfp void init() {
for (int i=0;i<TAN_TABS_SIZE;i++) {
// angle: in [0,TAN_MAX_VALUE_FOR_TABS].
double angle = i * TAN_DELTA_HI + i * TAN_DELTA_LO;
double sinAngle = StrictMath.sin(angle);
double cosAngle = StrictMath.cos(angle);
double cosAngleInv = 1/cosAngle;
double cosAngleInv2 = cosAngleInv*cosAngleInv;
double cosAngleInv3 = cosAngleInv2*cosAngleInv;
double cosAngleInv4 = cosAngleInv2*cosAngleInv2;
double cosAngleInv5 = cosAngleInv3*cosAngleInv2;
tanTab[i] = sinAngle * cosAngleInv;
tanDer1DivF1Tab[i] = cosAngleInv2;
tanDer2DivF2Tab[i] = ((2*sinAngle)*cosAngleInv3) * ONE_DIV_F2;
tanDer3DivF3Tab[i] = ((2*(1+2*sinAngle*sinAngle))*cosAngleInv4) * ONE_DIV_F3;
tanDer4DivF4Tab[i] = ((8*sinAngle*(2+sinAngle*sinAngle))*cosAngleInv5) * ONE_DIV_F4;
}
}
}
/**
* Max abs value for fast modulo, above which we use regular angle normalization.
* This value must be < (Integer.MAX_VALUE / TAN_INDEXER), to stay in range of int type.
* If too high, error gets larger because index-based reduction doesn't use an accurate
* enough definition of PI.
* If too low, error gets larger as well, because we use remainder into [-PI/2,PI/2],
* just provides a double, while index-based reduction is more accurate, using delta
* from index values and HI/LO values.
*/
static final double TAN_MAX_VALUE_FOR_INT_MODULO = (((Integer.MAX_VALUE>>9) / TAN_INDEXER) * 0.99);
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR ACOS, ASIN
//--------------------------------------------------------------------------
// We use the following formula:
// 1) acos(x) = PI/2 - asin(x)
// 2) asin(-x) = -asin(x)
// ---> we only have to compute asin(x) on [0,1].
// For values not close to +-1, we use look-up tables;
// for values near +-1, we use code derived from fdlibm.
/**
* Supposed to be >= sin(77.2deg), as fdlibm code is supposed to work with values > 0.975,
* but seems to work well enough as long as value >= sin(25deg).
*/
static final double ASIN_MAX_VALUE_FOR_TABS = StrictMath.sin(StrictMath.toRadians(73.0));
static final int ASIN_TABS_SIZE = (1<<getTabSizePower(13)) + 1;
static final double ASIN_DELTA = ASIN_MAX_VALUE_FOR_TABS/(ASIN_TABS_SIZE - 1);
static final double ASIN_INDEXER = 1/ASIN_DELTA;
static final class MyTAsin {
static final double[] asinTab = new double[ASIN_TABS_SIZE];
static final double[] asinDer1DivF1Tab = new double[ASIN_TABS_SIZE];
static final double[] asinDer2DivF2Tab = new double[ASIN_TABS_SIZE];
static final double[] asinDer3DivF3Tab = new double[ASIN_TABS_SIZE];
static final double[] asinDer4DivF4Tab = new double[ASIN_TABS_SIZE];
static {
init();
}
private static strictfp void init() {
for (int i=0;i<ASIN_TABS_SIZE;i++) {
// x: in [0,ASIN_MAX_VALUE_FOR_TABS].
double x = i * ASIN_DELTA;
double oneMinusXSqInv = 1/(1-x*x);
double oneMinusXSqInv0_5 = StrictMath.sqrt(oneMinusXSqInv);
double oneMinusXSqInv1_5 = oneMinusXSqInv0_5*oneMinusXSqInv;
double oneMinusXSqInv2_5 = oneMinusXSqInv1_5*oneMinusXSqInv;
double oneMinusXSqInv3_5 = oneMinusXSqInv2_5*oneMinusXSqInv;
asinTab[i] = StrictMath.asin(x);
asinDer1DivF1Tab[i] = oneMinusXSqInv0_5;
asinDer2DivF2Tab[i] = (x*oneMinusXSqInv1_5) * ONE_DIV_F2;
asinDer3DivF3Tab[i] = ((1+2*x*x)*oneMinusXSqInv2_5) * ONE_DIV_F3;
asinDer4DivF4Tab[i] = ((5+2*x*(2+x*(5-2*x)))*oneMinusXSqInv3_5) * ONE_DIV_F4;
}
}
}
static final double ASIN_MAX_VALUE_FOR_POWTABS = StrictMath.sin(StrictMath.toRadians(88.6));
static final int ASIN_POWTABS_POWER = 84;
static final double ASIN_POWTABS_ONE_DIV_MAX_VALUE = 1/ASIN_MAX_VALUE_FOR_POWTABS;
static final int ASIN_POWTABS_SIZE = (FM_USE_POWTABS_FOR_ASIN || SFM_USE_POWTABS_FOR_ASIN) ? (1<<getTabSizePower(12)) + 1 : 0;
static final int ASIN_POWTABS_SIZE_MINUS_ONE = ASIN_POWTABS_SIZE - 1;
static final class MyTAsinPow {
static final double[] asinParamPowTab = new double[ASIN_POWTABS_SIZE];
static final double[] asinPowTab = new double[ASIN_POWTABS_SIZE];
static final double[] asinDer1DivF1PowTab = new double[ASIN_POWTABS_SIZE];
static final double[] asinDer2DivF2PowTab = new double[ASIN_POWTABS_SIZE];
static final double[] asinDer3DivF3PowTab = new double[ASIN_POWTABS_SIZE];
static final double[] asinDer4DivF4PowTab = new double[ASIN_POWTABS_SIZE];
static {
init();
}
private static strictfp void init() {
if (FM_USE_POWTABS_FOR_ASIN || SFM_USE_POWTABS_FOR_ASIN) {
for (int i=0;i<ASIN_POWTABS_SIZE;i++) {
// x: in [0,ASIN_MAX_VALUE_FOR_POWTABS].
double x = StrictMath.pow(i*(1.0/ASIN_POWTABS_SIZE_MINUS_ONE), 1.0/ASIN_POWTABS_POWER) * ASIN_MAX_VALUE_FOR_POWTABS;
double oneMinusXSqInv = 1/(1-x*x);
double oneMinusXSqInv0_5 = StrictMath.sqrt(oneMinusXSqInv);
double oneMinusXSqInv1_5 = oneMinusXSqInv0_5*oneMinusXSqInv;
double oneMinusXSqInv2_5 = oneMinusXSqInv1_5*oneMinusXSqInv;
double oneMinusXSqInv3_5 = oneMinusXSqInv2_5*oneMinusXSqInv;
asinParamPowTab[i] = x;
asinPowTab[i] = StrictMath.asin(x);
asinDer1DivF1PowTab[i] = oneMinusXSqInv0_5;
asinDer2DivF2PowTab[i] = (x*oneMinusXSqInv1_5) * ONE_DIV_F2;
asinDer3DivF3PowTab[i] = ((1+2*x*x)*oneMinusXSqInv2_5) * ONE_DIV_F3;
asinDer4DivF4PowTab[i] = ((5+2*x*(2+x*(5-2*x)))*oneMinusXSqInv3_5) * ONE_DIV_F4;
}
}
}
}
static final double ASIN_PIO2_HI = Double.longBitsToDouble(0x3FF921FB54442D18L); // 1.57079632679489655800e+00
static final double ASIN_PIO2_LO = Double.longBitsToDouble(0x3C91A62633145C07L); // 6.12323399573676603587e-17
static final double ASIN_PS0 = Double.longBitsToDouble(0x3fc5555555555555L); // 1.66666666666666657415e-01
static final double ASIN_PS1 = Double.longBitsToDouble(0xbfd4d61203eb6f7dL); // -3.25565818622400915405e-01
static final double ASIN_PS2 = Double.longBitsToDouble(0x3fc9c1550e884455L); // 2.01212532134862925881e-01
static final double ASIN_PS3 = Double.longBitsToDouble(0xbfa48228b5688f3bL); // -4.00555345006794114027e-02
static final double ASIN_PS4 = Double.longBitsToDouble(0x3f49efe07501b288L); // 7.91534994289814532176e-04
static final double ASIN_PS5 = Double.longBitsToDouble(0x3f023de10dfdf709L); // 3.47933107596021167570e-05
static final double ASIN_QS1 = Double.longBitsToDouble(0xc0033a271c8a2d4bL); // -2.40339491173441421878e+00
static final double ASIN_QS2 = Double.longBitsToDouble(0x40002ae59c598ac8L); // 2.02094576023350569471e+00
static final double ASIN_QS3 = Double.longBitsToDouble(0xbfe6066c1b8d0159L); // -6.88283971605453293030e-01
static final double ASIN_QS4 = Double.longBitsToDouble(0x3fb3b8c5b12e9282L); // 7.70381505559019352791e-02
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR ATAN
//--------------------------------------------------------------------------
// We use the formula atan(-x) = -atan(x)
// ---> we only have to compute atan(x) on [0,+Infinity[.
// For values corresponding to angles not close to +-PI/2, we use look-up tables;
// for values corresponding to angles near +-PI/2, we use code derived from fdlibm.
/**
* Supposed to be >= tan(67.7deg), as fdlibm code is supposed to work with values > 2.4375.
*/
static final double ATAN_MAX_VALUE_FOR_TABS = StrictMath.tan(StrictMath.toRadians(74.0));
static final int ATAN_TABS_SIZE = (1<<getTabSizePower(12)) + 1;
static final double ATAN_DELTA = ATAN_MAX_VALUE_FOR_TABS/(ATAN_TABS_SIZE - 1);
static final double ATAN_INDEXER = 1/ATAN_DELTA;
static final class MyTAtan {
static final double[] atanTab = new double[ATAN_TABS_SIZE];
static final double[] atanDer1DivF1Tab = new double[ATAN_TABS_SIZE];
static final double[] atanDer2DivF2Tab = new double[ATAN_TABS_SIZE];
static final double[] atanDer3DivF3Tab = new double[ATAN_TABS_SIZE];
static final double[] atanDer4DivF4Tab = new double[ATAN_TABS_SIZE];
static {
init();
}
private static strictfp void init() {
for (int i=0;i<ATAN_TABS_SIZE;i++) {
// x: in [0,ATAN_MAX_VALUE_FOR_TABS].
double x = i * ATAN_DELTA;
double onePlusXSqInv = 1/(1+x*x);
double onePlusXSqInv2 = onePlusXSqInv*onePlusXSqInv;
double onePlusXSqInv3 = onePlusXSqInv2*onePlusXSqInv;
double onePlusXSqInv4 = onePlusXSqInv2*onePlusXSqInv2;
atanTab[i] = StrictMath.atan(x);
atanDer1DivF1Tab[i] = onePlusXSqInv;
atanDer2DivF2Tab[i] = (-2*x*onePlusXSqInv2) * ONE_DIV_F2;
atanDer3DivF3Tab[i] = ((-2+6*x*x)*onePlusXSqInv3) * ONE_DIV_F3;
atanDer4DivF4Tab[i] = ((24*x*(1-x*x))*onePlusXSqInv4) * ONE_DIV_F4;
}
}
}
static final double ATAN_HI3 = Double.longBitsToDouble(0x3ff921fb54442d18L); // 1.57079632679489655800e+00 atan(inf)hi
static final double ATAN_LO3 = Double.longBitsToDouble(0x3c91a62633145c07L); // 6.12323399573676603587e-17 atan(inf)lo
static final double ATAN_AT0 = Double.longBitsToDouble(0x3fd555555555550dL); // 3.33333333333329318027e-01
static final double ATAN_AT1 = Double.longBitsToDouble(0xbfc999999998ebc4L); // -1.99999999998764832476e-01
static final double ATAN_AT2 = Double.longBitsToDouble(0x3fc24924920083ffL); // 1.42857142725034663711e-01
static final double ATAN_AT3 = Double.longBitsToDouble(0xbfbc71c6fe231671L); // -1.11111104054623557880e-01
static final double ATAN_AT4 = Double.longBitsToDouble(0x3fb745cdc54c206eL); // 9.09088713343650656196e-02
static final double ATAN_AT5 = Double.longBitsToDouble(0xbfb3b0f2af749a6dL); // -7.69187620504482999495e-02
static final double ATAN_AT6 = Double.longBitsToDouble(0x3fb10d66a0d03d51L); // 6.66107313738753120669e-02
static final double ATAN_AT7 = Double.longBitsToDouble(0xbfadde2d52defd9aL); // -5.83357013379057348645e-02
static final double ATAN_AT8 = Double.longBitsToDouble(0x3fa97b4b24760debL); // 4.97687799461593236017e-02
static final double ATAN_AT9 = Double.longBitsToDouble(0xbfa2b4442c6a6c2fL); // -3.65315727442169155270e-02
static final double ATAN_AT10 = Double.longBitsToDouble(0x3f90ad3ae322da11L); // 1.62858201153657823623e-02
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR TANH
//--------------------------------------------------------------------------
/**
* Constant found experimentally:
* StrictMath.tanh(TANH_1_THRESHOLD) = 1,
* StrictMath.tanh(nextDown(TANH_1_THRESHOLD)) = FastMath.tanh(nextDown(TANH_1_THRESHOLD)) < 1.
*/
static final double TANH_1_THRESHOLD = 19.061547465398498;
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR ASINH AND ACOSH
//--------------------------------------------------------------------------
static final double ASINH_LOG1P_THRESHOLD = 0.04;
/**
* sqrt(x*x+-1) should yield higher threshold, but it's enough due to
* subsequent log.
*/
static final double ASINH_ACOSH_SQRT_ELISION_THRESHOLD = (1<<24);
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR EXP AND EXPM1
//--------------------------------------------------------------------------
static final double EXP_OVERFLOW_LIMIT = Double.longBitsToDouble(0x40862E42FEFA39EFL); // 7.09782712893383973096e+02
static final double EXP_UNDERFLOW_LIMIT = Double.longBitsToDouble(0xC0874910D52D3051L); // -7.45133219101941108420e+02
static final int EXP_LO_DISTANCE_TO_ZERO_POT = 0;
static final int EXP_LO_DISTANCE_TO_ZERO = (1<<EXP_LO_DISTANCE_TO_ZERO_POT);
static final int EXP_LO_TAB_SIZE_POT = getTabSizePower(11);
static final int EXP_LO_TAB_SIZE = (1<<EXP_LO_TAB_SIZE_POT)+1;
static final int EXP_LO_TAB_MID_INDEX = ((EXP_LO_TAB_SIZE-1)/2);
static final int EXP_LO_INDEXING = EXP_LO_TAB_MID_INDEX/EXP_LO_DISTANCE_TO_ZERO;
static final int EXP_LO_INDEXING_DIV_SHIFT = EXP_LO_TAB_SIZE_POT-1-EXP_LO_DISTANCE_TO_ZERO_POT;
static final class MyTExp {
static final double[] expHiTab = new double[1+(int)EXP_OVERFLOW_LIMIT-(int)EXP_UNDERFLOW_LIMIT];
static final double[] expLoPosTab = new double[EXP_LO_TAB_SIZE];
static final double[] expLoNegTab = new double[EXP_LO_TAB_SIZE];
static {
init();
}
private static strictfp void init() {
for (int i=(int)EXP_UNDERFLOW_LIMIT;i<=(int)EXP_OVERFLOW_LIMIT;i++) {
expHiTab[i-(int)EXP_UNDERFLOW_LIMIT] = StrictMath.exp(i);
}
for (int i=0;i<EXP_LO_TAB_SIZE;i++) {
// x: in [-EXPM1_DISTANCE_TO_ZERO,EXPM1_DISTANCE_TO_ZERO].
double x = -EXP_LO_DISTANCE_TO_ZERO + i/(double)EXP_LO_INDEXING;
// exp(x)
expLoPosTab[i] = StrictMath.exp(x);
// 1-exp(-x), accurately computed
expLoNegTab[i] = -StrictMath.expm1(-x);
}
}
}
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR LOG AND LOG1P
//--------------------------------------------------------------------------
static final int LOG_BITS = getTabSizePower(12);
static final int LOG_TAB_SIZE = (1<<LOG_BITS);
static final class MyTLog {
static final double[] logXLogTab = new double[LOG_TAB_SIZE];
static final double[] logXTab = new double[LOG_TAB_SIZE];
static final double[] logXInvTab = new double[LOG_TAB_SIZE];
static {
init();
}
private static strictfp void init() {
for (int i=0;i<LOG_TAB_SIZE;i++) {
// Exact to use inverse of tab size, since it is a power of two.
double x = 1+i*(1.0/LOG_TAB_SIZE);
logXLogTab[i] = StrictMath.log(x);
logXTab[i] = x;
logXInvTab[i] = 1/x;
}
}
}
//--------------------------------------------------------------------------
// TABLE FOR POWERS OF TWO
//--------------------------------------------------------------------------
static final int TWO_POW_TAB_SIZE = USE_TWO_POW_TAB ? (MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT)+1 : 0;
static final class MyTTwoPow {
static final double[] twoPowTab = new double[TWO_POW_TAB_SIZE];
static {
init();
}
private static strictfp void init() {
if (USE_TWO_POW_TAB) {
for (int i=MIN_DOUBLE_EXPONENT;i<=MAX_DOUBLE_EXPONENT;i++) {
twoPowTab[i-MIN_DOUBLE_EXPONENT] = NumbersUtils.twoPow(i);
}
}
}
}
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR SQRT
//--------------------------------------------------------------------------
static final int SQRT_LO_BITS = getTabSizePower(12);
static final int SQRT_LO_TAB_SIZE = (1<<SQRT_LO_BITS);
static final class MyTSqrt {
static final double[] sqrtXSqrtHiTab = new double[MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT+1];
static final double[] sqrtXSqrtLoTab = new double[SQRT_LO_TAB_SIZE];
static final double[] sqrtSlopeHiTab = new double[MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT+1];
static final double[] sqrtSlopeLoTab = new double[SQRT_LO_TAB_SIZE];
static {
init();
}
private static strictfp void init() {
for (int i=MIN_DOUBLE_EXPONENT;i<=MAX_DOUBLE_EXPONENT;i++) {
double twoPowExpDiv2 = StrictMath.pow(2.0,i*0.5);
sqrtXSqrtHiTab[i-MIN_DOUBLE_EXPONENT] = twoPowExpDiv2 * 0.5; // Half sqrt, to avoid overflows.
sqrtSlopeHiTab[i-MIN_DOUBLE_EXPONENT] = 1/twoPowExpDiv2;
}
sqrtXSqrtLoTab[0] = 1.0;
sqrtSlopeLoTab[0] = 1.0;
final long SQRT_LO_MASK = (0x3FF0000000000000L | (0x000FFFFFFFFFFFFFL>>SQRT_LO_BITS));
for (int i=1;i<SQRT_LO_TAB_SIZE;i++) {
long xBits = SQRT_LO_MASK | (((long)(i-1))<<(52-SQRT_LO_BITS));
double sqrtX = StrictMath.sqrt(Double.longBitsToDouble(xBits));
sqrtXSqrtLoTab[i] = sqrtX;
sqrtSlopeLoTab[i] = 1/sqrtX;
}
}
}
//--------------------------------------------------------------------------
// CONSTANTS AND TABLES FOR CBRT
//--------------------------------------------------------------------------
static final int CBRT_LO_BITS = getTabSizePower(12);
static final int CBRT_LO_TAB_SIZE = (1<<CBRT_LO_BITS);
// For CBRT_LO_BITS = 12:
// cbrtXCbrtLoTab[0] = 1.0.
// cbrtXCbrtLoTab[1] = cbrt(1. 000000000000 1111111111111111111111111111111111111111b)
// cbrtXCbrtLoTab[2] = cbrt(1. 000000000001 1111111111111111111111111111111111111111b)
// cbrtXCbrtLoTab[3] = cbrt(1. 000000000010 1111111111111111111111111111111111111111b)
// cbrtXCbrtLoTab[4] = cbrt(1. 000000000011 1111111111111111111111111111111111111111b)
// etc.
static final class MyTCbrt {
static final double[] cbrtXCbrtHiTab = new double[MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT+1];
static final double[] cbrtXCbrtLoTab = new double[CBRT_LO_TAB_SIZE];
static final double[] cbrtSlopeHiTab = new double[MAX_DOUBLE_EXPONENT-MIN_DOUBLE_EXPONENT+1];
static final double[] cbrtSlopeLoTab = new double[CBRT_LO_TAB_SIZE];
static {
init();
}
private static strictfp void init() {
for (int i=MIN_DOUBLE_EXPONENT;i<=MAX_DOUBLE_EXPONENT;i++) {
double twoPowExpDiv3 = StrictMath.pow(2.0,i*(1.0/3));
cbrtXCbrtHiTab[i-MIN_DOUBLE_EXPONENT] = twoPowExpDiv3 * 0.5; // Half cbrt, to avoid overflows.
cbrtSlopeHiTab[i-MIN_DOUBLE_EXPONENT] = (4.0/3)/(twoPowExpDiv3*twoPowExpDiv3);
}
cbrtXCbrtLoTab[0] = 1.0;
cbrtSlopeLoTab[0] = 1.0;
final long CBRT_LO_MASK = (0x3FF0000000000000L | (0x000FFFFFFFFFFFFFL>>CBRT_LO_BITS));
for (int i=1;i<CBRT_LO_TAB_SIZE;i++) {
long xBits = CBRT_LO_MASK | (((long)(i-1))<<(52-CBRT_LO_BITS));
double cbrtX = StrictMath.cbrt(Double.longBitsToDouble(xBits));
cbrtXCbrtLoTab[i] = cbrtX;
cbrtSlopeLoTab[i] = 1/(cbrtX*cbrtX);
}
}
}
//--------------------------------------------------------------------------
// CONSTANTS FOR HYPOT
//--------------------------------------------------------------------------
/**
* For using sqrt, to avoid overflow/underflow, we want values magnitude in
* [1/sqrt(Double.MAX_VALUE/n),sqrt(Double.MAX_VALUE/n)],
* n being the number of arguments.
*
* sqrt(Double.MAX_VALUE/2) = 9.480751908109176E153
* and
* sqrt(Double.MAX_VALUE/3) = 7.741001517595157E153
* so
* 2^511 = 6.7039039649712985E153
* works for both.
*/
static final double HYPOT_MAX_MAG = NumbersUtils.twoPow(511);
/**
* Large enough to get a value's magnitude back into [2^-511,2^511]
* from Double.MIN_VALUE or Double.MAX_VALUE, and small enough
* not to get it across that range (considering a 2*53 tolerance
* due to only checking magnitude of min/max value, and scaling
* all values together).
*/
static final double HYPOT_FACTOR = NumbersUtils.twoPow(750);
//--------------------------------------------------------------------------
// PUBLIC METHODS
//--------------------------------------------------------------------------
/**
* Ensures that all look-up tables are initialized - otherwise they are
* initialized lazily.
*/
public static void initTables() {
/*
* Taking care not to call init methods here, which would
* recompute tables each time (even though the computations
* should be identical, since done with strictfp and StrictMath).
*/
int antiOptim = 0;
antiOptim += MyTSinCos.sinTab.length;
antiOptim += MyTTan.tanTab.length;
antiOptim += MyTAsin.asinTab.length;
antiOptim += MyTAsinPow.asinPowTab.length;
antiOptim += MyTAtan.atanTab.length;
antiOptim += MyTExp.expHiTab.length;
antiOptim += MyTLog.logXTab.length;
antiOptim += MyTTwoPow.twoPowTab.length;
antiOptim += MyTSqrt.sqrtXSqrtHiTab.length;
antiOptim += MyTCbrt.cbrtXCbrtHiTab.length;
if (StrictMath.cos((double)antiOptim) == 0.0) {
// Can't happen, cos is never +-0.0.
throw new AssertionError();
}
}
/*
* logarithms
*/
/**
* @param value An integer value in [1,Integer.MAX_VALUE].
* @return The integer part of the logarithm, in base 2, of the specified value,
* i.e. a result in [0,30]
* @throws IllegalArgumentException if the specified value is <= 0.
*/
public static int log2(int value) {
return NumbersUtils.log2(value);
}
/**
* @param value An integer value in [1,Long.MAX_VALUE].
* @return The integer part of the logarithm, in base 2, of the specified value,
* i.e. a result in [0,62]
* @throws IllegalArgumentException if the specified value is <= 0.
*/
public static int log2(long value) {
return NumbersUtils.log2(value);
}
/*
* powers
*/
/**
* Returns the exact result, provided it's in double range,
* i.e. if power is in [-1074,1023].
*
* @param power An int power.
* @return 2^power as a double, or +-Infinity in case of overflow.
*/
public static double twoPow(int power) {
/*
* OK to have this method factored here even though it returns
* a floating point value, because it only does integer operations
* and only takes integer arguments, so should behave the same
* even if inlined into FP-wide context.
*/
if (USE_TWO_POW_TAB) {
if (power >= MIN_DOUBLE_EXPONENT) {
if (power <= MAX_DOUBLE_EXPONENT) { // Normal or subnormal.
return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT];
} else { // Overflow.
return Double.POSITIVE_INFINITY;
}
} else { // Underflow.
return 0.0;
}
} else {
return NumbersUtils.twoPow(power);
}
}
/**
* @param value An int value.
* @return value*value.
*/
public static int pow2(int value) {
return value*value;
}
/**
* @param value A long value.
* @return value*value.
*/
public static long pow2(long value) {
return value*value;
}
/**
* @param value An int value.
* @return value*value*value.
*/
public static int pow3(int value) {
return value*value*value;
}
/**
* @param value A long value.
* @return value*value*value.
*/
public static long pow3(long value) {
return value*value*value;
}
/*
* absolute values
*/
/**
* @param value An int value.
* @return The absolute value, except if value is Integer.MIN_VALUE, for which it returns Integer.MIN_VALUE.
*/
public static int abs(int value) {
if (FM_USE_JDK_MATH || SFM_USE_JDK_MATH) {
return Math.abs(value);
}
return NumbersUtils.abs(value);
}
/**
* @param value A long value.
* @return The absolute value, except if value is Long.MIN_VALUE, for which it returns Long.MIN_VALUE.
*/
public static long abs(long value) {
if (FM_USE_JDK_MATH || SFM_USE_JDK_MATH) {
return Math.abs(value);
}
return NumbersUtils.abs(value);
}
/*
* close values
*/
/**
* @param value A long value.
* @return The specified value as int.
* @throws ArithmeticException if the specified value is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
*/
public static int toIntExact(long value) {
return NumbersUtils.asInt(value);
}
/**
* @param value A long value.
* @return The closest int value in [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
*/
public static int toInt(long value) {
return NumbersUtils.toInt(value);
}
/*
* ranges
*/
/**
* @param min An int value.
* @param max An int value.
* @param value An int value.
* @return minValue if value < minValue, maxValue if value > maxValue, value otherwise.
*/
public static int toRange(int min, int max, int value) {
return NumbersUtils.toRange(min, max, value);
}
/**
* @param min A long value.
* @param max A long value.
* @param value A long value.
* @return min if value < min, max if value > max, value otherwise.
*/
public static long toRange(long min, long max, long value) {
return NumbersUtils.toRange(min, max, value);
}
/*
* unary operators (increment,decrement,negate)
*/
/**
* @param value An int value.
* @return The argument incremented by one.
* @throws ArithmeticException if the mathematical result
* is not in int range.
*/
public static int incrementExact(int value) {
if (value == Integer.MAX_VALUE) {
throw new ArithmeticException("integer overflow");
}
return value + 1;
}
/**
* @param value A long value.
* @return The argument incremented by one.
* @throws ArithmeticException if the mathematical result
* is not in long range.
*/
public static long incrementExact(long value) {
if (value == Long.MAX_VALUE) {
throw new ArithmeticException("long overflow");
}
return value + 1L;
}
/**
* @param value An int value.
* @return The argument incremented by one, or the argument
* if the mathematical result is not in int range.
*/
public static int incrementBounded(int value) {
if (value == Integer.MAX_VALUE) {
return value;
}
return value + 1;
}
/**
* @param value A long value.
* @return The argument incremented by one, or the argument
* if the mathematical result is not in long range.
*/
public static long incrementBounded(long value) {
if (value == Long.MAX_VALUE) {
return value;
}
return value + 1L;
}
/**
* @param value An int value.
* @return The argument decremented by one.
* @throws ArithmeticException if the mathematical result
* is not in int range.
*/
public static int decrementExact(int value) {
if (value == Integer.MIN_VALUE) {
throw new ArithmeticException("integer overflow");
}
return value - 1;
}
/**
* @param value A long value.
* @return The argument decremented by one.
* @throws ArithmeticException if the mathematical result
* is not in long range.
*/
public static long decrementExact(long value) {
if (value == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow");
}
return value - 1L;
}
/**
* @param value An int value.
* @return The argument decremented by one, or the argument
* if the mathematical result is not in int range.
*/
public static int decrementBounded(int value) {
if (value == Integer.MIN_VALUE) {
return value;
}
return value - 1;
}
/**
* @param value A long value.
* @return The argument decremented by one, or the argument
* if the mathematical result is not in long range.
*/
public static long decrementBounded(long value) {
if (value == Long.MIN_VALUE) {
return value;
}
return value - 1L;
}
/**
* @param value An int value.
* @return The argument negated.
* @throws ArithmeticException if the mathematical result
* is not in int range.
*/
public static int negateExact(int value) {
if (value == Integer.MIN_VALUE) {
throw new ArithmeticException("integer overflow");
}
return -value;
}
/**
* @param value A long value.
* @return The argument negated.
* @throws ArithmeticException if the mathematical result
* is not in long range.
*/
public static long negateExact(long value) {
if (value == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow");
}
return -value;
}
/**
* @param value An int value.
* @return The argument negated, or Integer.MAX_VALUE
* if the argument is Integer.MIN_VALUE.
*/
public static int negateBounded(int value) {
if (value == Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
}
return -value;
}
/**
* @param value A long value.
* @return The argument negated, or Long.MAX_VALUE
* if the argument is Long.MIN_VALUE.
*/
public static long negateBounded(long value) {
if (value == Long.MIN_VALUE) {
return Long.MAX_VALUE;
}
return -value;
}
/*
* binary operators (+,-,*)
*/
/**
* @param a An int value.
* @param b An int value.
* @return The mathematical result of a+b.
* @throws ArithmeticException if the mathematical result of a+b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
*/
public static int addExact(int a, int b) {
return NumbersUtils.plusExact(a, b);
}
/**
* @param a A long value.
* @param b A long value.
* @return The mathematical result of a+b.
* @throws ArithmeticException if the mathematical result of a+b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range.
*/
public static long addExact(long a, long b) {
return NumbersUtils.plusExact(a, b);
}
/**
* @param a An int value.
* @param b An int value.
* @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a+b.
*/
public static int addBounded(int a, int b) {
return NumbersUtils.plusBounded(a, b);
}
/**
* @param a A long value.
* @param b A long value.
* @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a+b.
*/
public static long addBounded(long a, long b) {
return NumbersUtils.plusBounded(a, b);
}
/**
* @param a An int value.
* @param b An int value.
* @return The mathematical result of a-b.
* @throws ArithmeticException if the mathematical result of a-b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
*/
public static int subtractExact(int a, int b) {
return NumbersUtils.minusExact(a, b);
}
/**
* @param a A long value.
* @param b A long value.
* @return The mathematical result of a-b.
* @throws ArithmeticException if the mathematical result of a-b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range.
*/
public static long subtractExact(long a, long b) {
return NumbersUtils.minusExact(a, b);
}
/**
* @param a An int value.
* @param b An int value.
* @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a-b.
*/
public static int subtractBounded(int a, int b) {
return NumbersUtils.minusBounded(a, b);
}
/**
* @param a A long value.
* @param b A long value.
* @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a-b.
*/
public static long subtractBounded(long a, long b) {
return NumbersUtils.minusBounded(a, b);
}
/**
* @param a An int value.
* @param b An int value.
* @return The mathematical result of a*b.
* @throws ArithmeticException if the mathematical result of a*b is not in [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
*/
public static int multiplyExact(int a, int b) {
return NumbersUtils.timesExact(a, b);
}
/**
* @param a A long value.
* @param b An int value.
* @return The mathematical result of a*b.
* @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range.
*/
public static long multiplyExact(long a, int b) {
return NumbersUtils.timesExact(a, (long) b);
}
/**
* @param a A long value.
* @param b A long value.
* @return The mathematical result of a*b.
* @throws ArithmeticException if the mathematical result of a*b is not in [Long.MIN_VALUE,Long.MAX_VALUE] range.
*/
public static long multiplyExact(long a, long b) {
return NumbersUtils.timesExact(a, b);
}
/**
* @param a An int value.
* @param b An int value.
* @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is the closest to mathematical result of a*b.
*/
public static int multiplyBounded(int a, int b) {
return NumbersUtils.timesBounded(a, b);
}
/**
* @param a A long value.
* @param b An int value.
* @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b.
*/
public static long multiplyBounded(long a, int b) {
return NumbersUtils.timesBounded(a, (long) b);
}
/**
* @param a A long value.
* @param b A long value.
* @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the closest to mathematical result of a*b.
*/
public static long multiplyBounded(long a, long b) {
return NumbersUtils.timesBounded(a, b);
}
/**
* @param x An int value.
* @param y An int value.
* @return The mathematical product as a long.
*/
public static long multiplyFull(int x, int y) {
return ((long) x) * ((long) y);
}
/**
* @param x A long value.
* @param y A long value.
* @return The most significant 64 bits of the 128-bit product of two 64-bit factors.
*/
public static long multiplyHigh(long x, long y) {
if ((x|y) < 0) {
// Use technique from section 8-2 of Henry S. Warren, Jr.,
// Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 173-174.
long x1 = (x >> 32);
long y1 = (y >> 32);
long x2 = (x & 0xFFFFFFFFL);
long y2 = (y & 0xFFFFFFFFL);
long z2 = x2 * y2;
long t = x1 * y2 + (z2 >>> 32);
long z1 = (t & 0xFFFFFFFFL) + x2 * y1;
long z0 = (t >> 32);
return x1 * y1 + z0 + (z1 >> 32);
} else {
// Use Karatsuba technique with two base 2^32 digits.
long x1 = (x >>> 32);
long y1 = (y >>> 32);
long x2 = (x & 0xFFFFFFFFL);
long y2 = (y & 0xFFFFFFFFL);
long A = x1 * y1;
long B = x2 * y2;
long C = (x1 + x2) * (y1 + y2);
long K = C - A - B;
return (((B >>> 32) + K) >>> 32) + A;
}
}
/*
* binary operators (/,%)
*/
/**
* Returns the largest int <= dividend/divisor.
*
* Unlike "/" operator, which rounds towards 0, this division
* rounds towards -Infinity (which give different result
* when the exact result is negative).
*
* @param x The dividend.
* @param y The divisor.
* @return The largest int <= dividend/divisor, unless dividend is
* Integer.MIN_VALUE and divisor is -1, in which case
* Integer.MIN_VALUE is returned.
* @throws ArithmeticException if the divisor is zero.
*/
public static int floorDiv(int x, int y) {
int r = x / y;
// If the signs are different and modulo not zero, rounding down.
if (((x ^ y) < 0) && ((r * y) != x)) {
r--;
}
return r;
}
/**
* Returns the largest long <= dividend/divisor.
*
* Unlike "/" operator, which rounds towards 0, this division
* rounds towards -Infinity (which give different result
* when the exact result is negative).
*
* @param x The dividend.
* @param y The divisor.
* @return The largest long <= dividend/divisor, unless dividend is
* Long.MIN_VALUE and divisor is -1, in which case
* Long.MIN_VALUE is returned.
* @throws ArithmeticException if the divisor is zero.
*/
public static long floorDiv(long x, int y) {
return floorDiv(x, (long) y);
}
/**
* Returns the largest long <= dividend/divisor.
*
* Unlike "/" operator, which rounds towards 0, this division
* rounds towards -Infinity (which give different result
* when the exact result is negative).
*
* @param x The dividend.
* @param y The divisor.
* @return The largest long <= dividend/divisor, unless dividend is
* Long.MIN_VALUE and divisor is -1, in which case
* Long.MIN_VALUE is returned.
* @throws ArithmeticException if the divisor is zero.
*/
public static long floorDiv(long x, long y) {
long r = x / y;
// If the signs are different and modulo not zero, rounding down.
if (((x ^ y) < 0) && ((r * y) != x)) {
r--;
}
return r;
}
/**
* Returns the floor modulus, which is "x - floorDiv(x,y) * y",
* has the same sign as y, and is in ]-abs(y),abs(y)[.
*
* The relationship between floorMod and floorDiv is the same
* than between "%" and "/".
*
* @param x The dividend.
* @param y The divisor.
* @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)".
* @throws ArithmeticException if the divisor is zero.
*/
public static int floorMod(int x, int y) {
return x - floorDiv(x, y) * y;
}
/**
* Returns the floor modulus, which is "x - floorDiv(x,y) * y",
* has the same sign as y, and is in ]-abs(y),abs(y)[.
*
* The relationship between floorMod and floorDiv is the same
* than between "%" and "/".
*
* @param x The dividend.
* @param y The divisor.
* @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)".
* @throws ArithmeticException if the divisor is zero.
*/
public static int floorMod(long x, int y) {
// No overflow so can cast.
return (int) (x - floorDiv(x,y) * y);
}
/**
* Returns the floor modulus, which is "x - floorDiv(x,y) * y",
* has the same sign as y, and is in ]-abs(y),abs(y)[.
*
* The relationship between floorMod and floorDiv is the same
* than between "%" and "/".
*
* @param x The dividend.
* @param y The divisor.
* @return The floor modulus, i.e. "x - (floorDiv(x, y) * y)".
* @throws ArithmeticException if the divisor is zero.
*/
public static long floorMod(long x, long y) {
return x - floorDiv(x, y) * y;
}
/*
* Non-redefined Math public values and treatments.
*/
public static int min(int a, int b) {
return Math.min(a,b);
}
public static long min(long a, long b) {
return Math.min(a,b);
}
public static int max(int a, int b) {
return Math.max(a,b);
}
public static long max(long a, long b) {
return Math.max(a,b);
}
//--------------------------------------------------------------------------
// PACKAGE-PRIVATE METHODS
//--------------------------------------------------------------------------
/**
* @param power Must be in normal values range.
*/
static double twoPowNormal(int power) {
if (USE_TWO_POW_TAB) {
return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT];
} else {
return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52);
}
}
/**
* @param power Must be in normal or subnormal values range.
*/
static double twoPowNormalOrSubnormal(int power) {
if (USE_TWO_POW_TAB) {
return MyTTwoPow.twoPowTab[power-MIN_DOUBLE_EXPONENT];
} else {
if (power <= -MAX_DOUBLE_EXPONENT) { // Not normal.
return Double.longBitsToDouble(0x0008000000000000L>>(-(power+MAX_DOUBLE_EXPONENT)));
} else { // Normal.
return Double.longBitsToDouble(((long)(power+MAX_DOUBLE_EXPONENT))<<52);
}
}
}
static double atan2_pinf_yyy(double y) {
if (y == Double.POSITIVE_INFINITY) {
return Math.PI/4;
} else if (y == Double.NEGATIVE_INFINITY) {
return -Math.PI/4;
} else if (y > 0.0) {
return 0.0;
} else if (y < 0.0) {
return -0.0;
} else {
return Double.NaN;
}
}
static double atan2_ninf_yyy(double y) {
if (y == Double.POSITIVE_INFINITY) {
return 3*Math.PI/4;
} else if (y == Double.NEGATIVE_INFINITY) {
return -3*Math.PI/4;
} else if (y > 0.0) {
return Math.PI;
} else if (y < 0.0) {
return -Math.PI;
} else {
return Double.NaN;
}
}
static double atan2_yyy_zeroOrNaN(double y, double x) {
if (x == 0.0) {
if (y == 0.0) {
if (signFromBit_antiCyclic(x) < 0) {
// x is -0.0
return signFromBit_antiCyclic(y) * Math.PI;
} else {
// +-0.0
return y;
}
}
if (y > 0.0) {
return Math.PI/2;
} else if (y < 0.0) {
return -Math.PI/2;
} else {
return Double.NaN;
}
} else {
return Double.NaN;
}
}
/**
* At least one of the arguments must be NaN.
*/
static double hypot_NaN(double xAbs, double yAbs) {
if ((xAbs == Double.POSITIVE_INFINITY) || (yAbs == Double.POSITIVE_INFINITY)) {
return Double.POSITIVE_INFINITY;
} else {
return Double.NaN;
}
}
/**
* At least one of the arguments must be NaN.
*/
static double hypot_NaN(double xAbs, double yAbs, double zAbs) {
if ((xAbs == Double.POSITIVE_INFINITY) || (yAbs == Double.POSITIVE_INFINITY) || (zAbs == Double.POSITIVE_INFINITY)) {
return Double.POSITIVE_INFINITY;
} else {
return Double.NaN;
}
}
/*
*
*/
/**
* @param remainder Must have 1 for 2nd and 3rd exponent bits, which is the
* case for heavyRemPiO2 remainders (their absolute values are >=
* Double.longBitsToDouble(0x3000000000000000L)
* = 1.727233711018889E-77, and even if they were not, turning these
* bits from 0 to 1 on decoding would not change the absolute error
* much), and also works for +-Infinity or NaN encoding.
* @param quadrant Must be in [0,3].
* @return Bits holding remainder, and quadrant instead of
* reamainder's 2nd and 3rd exponent bits.
*/
static long encodeRemainderAndQuadrant(double remainder, int quadrant) {
final long bits = Double.doubleToRawLongBits(remainder);
return (bits&QUADRANT_BITS_0_MASK)|(((long)quadrant)<<60);
}
static double decodeRemainder(long bits) {
return Double.longBitsToDouble((bits&QUADRANT_BITS_0_MASK)|QUADRANT_PLACE_BITS);
}
static int decodeQuadrant(long bits) {
return ((int)(bits>>60))&3;
}
/*
* JDK-based remainders.
* Since a strict one for (% (PI/2)) is needed for heavyRemainderPiO2,
* we need it in this class.
* Then, for homogeneity, we put them all in this class.
* Then, to avoid code duplication for these slow-anyway methods,
* we just stick with strict versions, for both FastMath and StrictFastMath.
*/
/**
* @param angle Angle, in radians.
* @return Remainder of (angle % (2*PI)), in [-PI,PI].
*/
static strictfp double jdkRemainderTwoPi(double angle) {
final double sin = StrictMath.sin(angle);
final double cos = StrictMath.cos(angle);
return StrictMath.atan2(sin, cos);
}
/**
* @param angle Angle, in radians.
* @return Remainder of (angle % PI), in [-PI/2,PI/2].
*/
static strictfp double jdkRemainderPi(double angle) {
final double sin = StrictMath.sin(angle);
final double cos = StrictMath.cos(angle);
/*
* Making sure atan2's result ends up in [-PI/2,PI/2],
* i.e. has maximum accuracy.
*/
return StrictMath.atan2(sin, Math.abs(cos));
}
/**
* @param angle Angle, in radians.
* @return Bits of double corresponding to remainder of (angle % (PI/2)),
* in [-PI/4,PI/4], with quadrant encoded in exponent bits.
*/
static strictfp long jdkRemainderPiO2(double angle, boolean negateRem) {
final double sin = StrictMath.sin(angle);
final double cos = StrictMath.cos(angle);
/*
* Computing quadrant first, and then computing
* atan2, to make sure its result ends up in [-PI/4,PI/4],
* i.e. has maximum accuracy.
*/
final int q;
final double sinForAtan2;
final double cosForAtan2;
if (cos >= (SQRT_2/2)) {
// [-PI/4,PI/4]
q = 0;
sinForAtan2 = sin;
cosForAtan2 = cos;
} else if (cos <= -(SQRT_2/2)) {
// [3*PI/4,5*PI/4]
q = 2;
sinForAtan2 = -sin;
cosForAtan2 = -cos;
} else if (sin > 0.0) {
// [PI/4,3*PI/4]
q = 1;
sinForAtan2 = -cos;
cosForAtan2 = sin;
} else {
// [5*PI/4,7*PI/4]
q = 3;
sinForAtan2 = cos;
cosForAtan2 = -sin;
}
double fw = StrictMath.atan2(sinForAtan2, cosForAtan2);
return encodeRemainderAndQuadrant(negateRem ? -fw : fw, q);
}
/*
* Our remainders implementations.
*/
/**
* @param angle Angle, in radians. Must not be NaN nor +-Infinity.
* @return Remainder of (angle % (2*PI)), in [-PI,PI].
*/
static strictfp double heavyRemainderTwoPi(double angle) {
final long remAndQuad = heavyRemainderPiO2(angle, false);
final double rem = decodeRemainder(remAndQuad);
final int q = decodeQuadrant(remAndQuad);
if (q == 0) {
return rem;
} else if (q == 1) {
return (rem + PIO2_LO) + PIO2_HI;
} else if (q == 2) {
if (rem < 0.0) {
return (rem + PI_LO) + PI_HI;
} else {
return (rem - PI_LO) - PI_HI;
}
} else {
return (rem - PIO2_LO) - PIO2_HI;
}
}
/**
* @param angle Angle, in radians. Must not be NaN nor +-Infinity.
* @return Remainder of (angle % PI), in [-PI/2,PI/2].
*/
static strictfp double heavyRemainderPi(double angle) {
final long remAndQuad = heavyRemainderPiO2(angle, false);
final double rem = decodeRemainder(remAndQuad);
final int q = decodeQuadrant(remAndQuad);
if ((q&1) != 0) {
// q is 1 or 3
if (rem < 0.0) {
return (rem + PIO2_LO) + PIO2_HI;
} else {
return (rem - PIO2_LO) - PIO2_HI;
}
}
return rem;
}
/**
* Remainder using an accurate definition of PI.
* Derived from a fdlibm treatment called __kernel_rem_pio2.
*
* Not defining a non-strictfp version for FastMath, to avoid duplicating
* its long and messy code, and because it's slow anyway, and should be
* rarely used when speed matters.
*
* @param angle Angle, in radians. Must not be NaN nor +-Infinity.
* @param negateRem True if remainder must be negated before encoded into returned long.
* @return Bits of double corresponding to remainder of (angle % (PI/2)),
* in [-PI/4,PI/4], with quadrant encoded in exponent bits.
*/
static strictfp long heavyRemainderPiO2(double angle, boolean negateRem) {
/*
* fdlibm treatments unrolled, to avoid garbage and be OOME-free,
* corresponding to:
* 1) initial jk = 4 (precision = 3 = 64 bits (extended)),
* which is more accurate than using precision = 2
* (53 bits, double), even though we work with doubles
* and use strictfp!
* 2) max lengths of 8 for f[], 6 for q[], fq[] and iq[].
* 3) at most one recomputation (one goto).
* These limitations were experimentally found to
* be sufficient for billions of random doubles
* of random magnitudes.
* For the rare cases that our unrolled treatments can't handle,
* we fall back to a JDK-based implementation.
*/
int n,i,j,ih;
double fw;
/*
* Turning angle into 24-bits integer chunks.
* Done outside __kernel_rem_pio2, but we factor it inside our method.
*/
// Reworking exponent to have a value < 2^24.
final long lx = Double.doubleToRawLongBits(angle);
final long exp = ((lx>>52)&0x7FF) - (1023+23);
double z = Double.longBitsToDouble(lx - (exp<<52));
double x0 = (double)(int)z;
z = (z-x0)*TWO_POW_24;
double x1 = (double)(int)z;
z = (z-x1)*TWO_POW_24;
double x2 = (double)(int)z;
final int e0 = (int)exp;
// in [1,3]
final int nx = (x2 == 0.0) ? ((x1 == 0.0) ? 1 : 2) : 3;
/*
*
*/
double f0,f1,f2,f3,f4,f5,f6,f7;
double q0,q1,q2,q3,q4,q5;
int iq0,iq1,iq2,iq3,iq4,iq5;
int jk = 4;
int jx = nx-1;
int jv = Math.max(0,(e0-3)/24);
// In fdlibm, this is q0, but we prefer to use q0 for q[0].
int qZero = e0-24*(jv+1);
j = jv-jx;
if (jx == 0) {
f6 = 0.0;
f5 = 0.0;
f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0;
f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0;
f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0;
f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0;
f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0;
q0 = x0*f0;
q1 = x0*f1;
q2 = x0*f2;
q3 = x0*f3;
q4 = x0*f4;
} else if (jx == 1) {
f6 = 0.0;
f5 = (j >= -5) ? TWO_OVER_PI_TAB[j+5] : 0.0;
f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0;
f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0;
f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0;
f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0;
f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0;
q0 = x0*f1 + x1*f0;
q1 = x0*f2 + x1*f1;
q2 = x0*f3 + x1*f2;
q3 = x0*f4 + x1*f3;
q4 = x0*f5 + x1*f4;
} else { // jx == 2
f6 = (j >= -6) ? TWO_OVER_PI_TAB[j+6] : 0.0;
f5 = (j >= -5) ? TWO_OVER_PI_TAB[j+5] : 0.0;
f4 = (j >= -4) ? TWO_OVER_PI_TAB[j+4] : 0.0;
f3 = (j >= -3) ? TWO_OVER_PI_TAB[j+3] : 0.0;
f2 = (j >= -2) ? TWO_OVER_PI_TAB[j+2] : 0.0;
f1 = (j >= -1) ? TWO_OVER_PI_TAB[j+1] : 0.0;
f0 = (j >= 0) ? TWO_OVER_PI_TAB[j] : 0.0;
q0 = x0*f2 + x1*f1 + x2*f0;
q1 = x0*f3 + x1*f2 + x2*f1;
q2 = x0*f4 + x1*f3 + x2*f2;
q3 = x0*f5 + x1*f4 + x2*f3;
q4 = x0*f6 + x1*f5 + x2*f4;
}
double twoPowQZero = twoPowNormal(qZero);
int jz = jk;
/*
* Unrolling of first round.
*/
z = q4;
fw = (double)(int)(TWO_POW_N24*z);
iq0 = (int)(z-TWO_POW_24*fw);
z = q3+fw;
fw = (double)(int)(TWO_POW_N24*z);
iq1 = (int)(z-TWO_POW_24*fw);
z = q2+fw;
fw = (double)(int)(TWO_POW_N24*z);
iq2 = (int)(z-TWO_POW_24*fw);
z = q1+fw;
fw = (double)(int)(TWO_POW_N24*z);
iq3 = (int)(z-TWO_POW_24*fw);
z = q0+fw;
iq4 = 0;
iq5 = 0;
z = (z*twoPowQZero) % 8.0;
n = (int)z;
z -= (double)n;
ih = 0;
if (qZero > 0) {
// Parentheses against code formatter bug.
i = (iq3>>(24-qZero));
n += i;
iq3 -= i<<(24-qZero);
ih = iq3>>(23-qZero);
} else if (qZero == 0) {
ih = iq3>>23;
} else if (z >= 0.5) {
ih = 2;
}
if (ih > 0) {
n += 1;
// carry = 1 is common case,
// so using it as initial value.
int carry = 1;
if (iq0 != 0) {
iq0 = 0x1000000 - iq0;
iq1 = 0xFFFFFF - iq1;
iq2 = 0xFFFFFF - iq2;
iq3 = 0xFFFFFF - iq3;
} else if (iq1 != 0) {
iq1 = 0x1000000 - iq1;
iq2 = 0xFFFFFF - iq2;
iq3 = 0xFFFFFF - iq3;
} else if (iq2 != 0) {
iq2 = 0x1000000 - iq2;
iq3 = 0xFFFFFF - iq3;
} else if (iq3 != 0) {
iq3 = 0x1000000 - iq3;
} else {
carry = 0;
}
if (qZero > 0) {
if (qZero == 1) {
iq3 &= 0x7FFFFF;
} else if (qZero == 2) {
iq3 &= 0x3FFFFF;
}
}
if (ih == 2) {
z = 1.0 - z;
if (carry != 0) {
z -= twoPowQZero;
}
}
}
if (z == 0.0) {
if (iq3 == 0) {
// With random values of random magnitude,
// probability for this to happen seems lower than 1e-6.
// jz would be more than just incremented by one,
// which our unrolling doesn't support.
return jdkRemainderPiO2(angle, negateRem);
}
if (jx == 0) {
f5 = TWO_OVER_PI_TAB[jv+5];
q5 = x0*f5;
} else if (jx == 1) {
f6 = TWO_OVER_PI_TAB[jv+5];
q5 = x0*f6 + x1*f5;
} else { // jx == 2
f7 = TWO_OVER_PI_TAB[jv+5];
q5 = x0*f7 + x1*f6 + x2*f5;
}
jz++;
/*
* Unrolling of second round.
*/
z = q5;
fw = (double)(int)(TWO_POW_N24*z);
iq0 = (int)(z-TWO_POW_24*fw);
z = q4+fw;
fw = (double)(int)(TWO_POW_N24*z);
iq1 = (int)(z-TWO_POW_24*fw);
z = q3+fw;
fw = (double)(int)(TWO_POW_N24*z);
iq2 = (int)(z-TWO_POW_24*fw);
z = q2+fw;
fw = (double)(int)(TWO_POW_N24*z);
iq3 = (int)(z-TWO_POW_24*fw);
z = q1+fw;
fw = (double)(int)(TWO_POW_N24*z);
iq4 = (int)(z-TWO_POW_24*fw);
z = q0+fw;
iq5 = 0;
z = (z*twoPowQZero) % 8.0;
n = (int)z;
z -= (double)n;
ih = 0;
if (qZero > 0) {
// Parentheses against code formatter bug.
i = (iq4>>(24-qZero));
n += i;
iq4 -= i<<(24-qZero);
ih = iq4>>(23-qZero);
} else if (qZero == 0) {
ih = iq4>>23;
} else if (z >= 0.5) {
ih = 2;
}
if (ih > 0) {
n += 1;
// carry = 1 is common case,
// so using it as initial value.
int carry = 1;
if (iq0 != 0) {
iq0 = 0x1000000 - iq0;
iq1 = 0xFFFFFF - iq1;
iq2 = 0xFFFFFF - iq2;
iq3 = 0xFFFFFF - iq3;
iq4 = 0xFFFFFF - iq4;
} else if (iq1 != 0) {
iq1 = 0x1000000 - iq1;
iq2 = 0xFFFFFF - iq2;
iq3 = 0xFFFFFF - iq3;
iq4 = 0xFFFFFF - iq4;
} else if (iq2 != 0) {
iq2 = 0x1000000 - iq2;
iq3 = 0xFFFFFF - iq3;
iq4 = 0xFFFFFF - iq4;
} else if (iq3 != 0) {
iq3 = 0x1000000 - iq3;
iq4 = 0xFFFFFF - iq4;
} else if (iq4 != 0) {
iq4 = 0x1000000 - iq4;
} else {
carry = 0;
}
if (qZero > 0) {
if (qZero == 1) {
iq4 &= 0x7FFFFF;
} else if (qZero == 2) {
iq4 &= 0x3FFFFF;
}
}
if (ih == 2) {
z = 1.0 - z;
if (carry != 0) {
z -= twoPowQZero;
}
}
}
if (z == 0.0) {
if (iq4 == 0) {
// Case not encountered in tests, but still handling it.
// Would require a third loop unrolling.
return jdkRemainderPiO2(angle, negateRem);
} else {
// z == 0.0, and iq4 != 0,
// so we remove 24 from qZero only once,
// but since we no longer use qZero,
// we just bother to multiply its 2-power
// by 2^-24.
jz--;
twoPowQZero *= TWO_POW_N24;
}
} else {
// z != 0.0 at end of second round.
}
} else {
// z != 0.0 at end of first round.
}
/*
* After loop.
*/
if (z != 0.0) {
z /= twoPowQZero;
if (z >= TWO_POW_24) {
fw = (double)(int)(TWO_POW_N24*z);
if (jz == jk) {
iq4 = (int)(z-TWO_POW_24*fw);
jz++; // jz to 5
// Not using qZero anymore so not updating it.
twoPowQZero *= TWO_POW_24;
iq5 = (int)fw;
} else { // jz == jk+1 == 5
// Case not encountered in tests, but still handling it.
// Would require use of iq6, with jz = 6.
return jdkRemainderPiO2(angle, negateRem);
}
} else {
if (jz == jk) {
iq4 = (int)z;
} else { // jz == jk+1 == 5
// Case not encountered in tests, but still handling it.
iq5 = (int)z;
}
}
}
fw = twoPowQZero;
if (jz == 5) {
q5 = fw*(double)iq5;
fw *= TWO_POW_N24;
} else {
q5 = 0.0;
}
q4 = fw*(double)iq4;
fw *= TWO_POW_N24;
q3 = fw*(double)iq3;
fw *= TWO_POW_N24;
q2 = fw*(double)iq2;
fw *= TWO_POW_N24;
q1 = fw*(double)iq1;
fw *= TWO_POW_N24;
q0 = fw*(double)iq0;
/*
* We just use HI part of the result.
*/
fw = PIO2_TAB0*q5;
fw += PIO2_TAB0*q4 + PIO2_TAB1*q5;
fw += PIO2_TAB0*q3 + PIO2_TAB1*q4 + PIO2_TAB2*q5;
fw += PIO2_TAB0*q2 + PIO2_TAB1*q3 + PIO2_TAB2*q4 + PIO2_TAB3*q5;
fw += PIO2_TAB0*q1 + PIO2_TAB1*q2 + PIO2_TAB2*q3 + PIO2_TAB3*q4 + PIO2_TAB4*q5;
fw += PIO2_TAB0*q0 + PIO2_TAB1*q1 + PIO2_TAB2*q2 + PIO2_TAB3*q3 + PIO2_TAB4*q4 + PIO2_TAB5*q5;
if ((ih != 0) ^ negateRem) {
fw = -fw;
}
return encodeRemainderAndQuadrant(fw, n&3);
}
//--------------------------------------------------------------------------
// PRIVATE METHODS
//--------------------------------------------------------------------------
/**
* Redefined here, to avoid cyclic dependency with (Strict)FastMath.
*
* @param value A double value.
* @return -1 if sign bit is 1, 1 if sign bit is 0.
*/
private static long signFromBit_antiCyclic(double value) {
// Returning a long, to avoid useless cast into int.
return ((Double.doubleToRawLongBits(value)>>62)|1);
}
private static boolean getBooleanProperty(
final String key,
boolean defaultValue) {
final String tmp = System.getProperty(key);
if (tmp != null) {
return Boolean.parseBoolean(tmp);
} else {
return defaultValue;
}
}
/**
* Use look-up tables size power through this method,
* to make sure is it small in case java.lang.Math
* is directly used.
*/
private static int getTabSizePower(int tabSizePower) {
return (FM_USE_JDK_MATH && SFM_USE_JDK_MATH) ? Math.min(2, tabSizePower) : tabSizePower;
}
}