Added all Java 8 StrictMath methods to FastMath.
This change allows FastMath to remain compatible with newer Java versions, despite it stiil requires only Java 5 to compile and run. JIRA: MATH-1156
This commit is contained in:
parent
cee04d1648
commit
a67f0a33e6
6
pom.xml
6
pom.xml
|
@ -38,9 +38,9 @@
|
|||
</issueManagement>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/math/trunk</connection>
|
||||
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/math/trunk</developerConnection>
|
||||
<url>http://svn.apache.org/viewvc/commons/proper/math/trunk</url>
|
||||
<connection>scm:git:http://git-wip-us.apache.org/repos/asf/commons-math.git</connection>
|
||||
<developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/commons-math.git</developerConnection>
|
||||
<url>https://git-wip-us.apache.org/repos/asf?p=commons-math.git</url>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
|
|
|
@ -73,6 +73,10 @@ Users are encouraged to upgrade to this version as this release not
|
|||
2. A few methods in the FastMath class are in fact slower that their
|
||||
counterpart in either Math or StrictMath (cf. MATH-740 and MATH-901).
|
||||
">
|
||||
<action dev="luc" type="add" issue="MATH-1156" >
|
||||
Added all Java 8 StrictMath methods to FastMath, so FastMath remains compatible
|
||||
with newer Java versions.
|
||||
</action>
|
||||
<action dev="tn" type="add" issue="MATH-1139" due-to="Alexey Volkov">
|
||||
Added Gumbel, Laplace, Logistic and Nakagami distributions.
|
||||
</action>
|
||||
|
|
|
@ -293,6 +293,7 @@ public enum LocalizedFormats implements Localizable {
|
|||
OVERFLOW_IN_FRACTION("overflow in fraction {0}/{1}, cannot negate"),
|
||||
OVERFLOW_IN_ADDITION("overflow in addition: {0} + {1}"),
|
||||
OVERFLOW_IN_SUBTRACTION("overflow in subtraction: {0} - {1}"),
|
||||
OVERFLOW_IN_MULTIPLICATION("overflow in multiplication: {0} * {1}"),
|
||||
PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD("cannot access {0} method in percentile implementation {1}"),
|
||||
PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD("percentile implementation {0} does not support {1}"),
|
||||
PERMUTATION_EXCEEDS_N("permutation size ({0}) exceeds permuation domain ({1})"), /* keep */
|
||||
|
|
|
@ -18,6 +18,9 @@ package org.apache.commons.math3.util;
|
|||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.apache.commons.math3.exception.MathArithmeticException;
|
||||
import org.apache.commons.math3.exception.util.LocalizedFormats;
|
||||
|
||||
/**
|
||||
* Faster, more accurate, portable alternative to {@link Math} and
|
||||
* {@link StrictMath} for large scale computation.
|
||||
|
@ -804,6 +807,24 @@ public class FastMath {
|
|||
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
|
||||
|
@ -3634,6 +3655,319 @@ public class FastMath {
|
|||
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).
|
||||
* </p>
|
||||
* @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).
|
||||
* </p>
|
||||
* @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).
|
||||
* </p>
|
||||
* @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).
|
||||
* </p>
|
||||
* @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.
|
||||
|
|
|
@ -265,6 +265,7 @@ OVERFLOW = d\u00e9passement de capacit\u00e9
|
|||
OVERFLOW_IN_FRACTION = d\u00e9passement de capacit\u00e9 pour la fraction {0}/{1}, son signe ne peut \u00eatre chang\u00e9
|
||||
OVERFLOW_IN_ADDITION = d\u00e9passement de capacit\u00e9 pour l''addition : {0} + {1}
|
||||
OVERFLOW_IN_SUBTRACTION = d\u00e9passement de capacit\u00e9 pour la soustraction : {0} - {1}
|
||||
OVERFLOW_IN_MULTIPLICATION = d\u00e9passement de capacit\u00e9 pour la multiplication : {0} * {1}
|
||||
PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD = acc\u00e8s impossible \u00e0 la m\u00e9thode {0} dans la mise en \u0153uvre du pourcentage {1}
|
||||
PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD = l''implantation de pourcentage {0} ne dispose pas de la m\u00e9thode {1}
|
||||
PERMUTATION_EXCEEDS_N = la taille de la permutation ({0}) d\u00e9passe le domaine de la permutation ({1})
|
||||
|
|
|
@ -23,14 +23,13 @@ import java.util.Locale;
|
|||
import java.util.ResourceBundle;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class LocalizedFormatsTest {
|
||||
|
||||
@Test
|
||||
public void testMessageNumber() {
|
||||
Assert.assertEquals(319, LocalizedFormats.values().length);
|
||||
Assert.assertEquals(320, LocalizedFormats.values().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -19,13 +19,16 @@ package org.apache.commons.math3.util;
|
|||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.apache.commons.math3.TestUtils;
|
||||
import org.apache.commons.math3.dfp.Dfp;
|
||||
import org.apache.commons.math3.dfp.DfpField;
|
||||
import org.apache.commons.math3.dfp.DfpMath;
|
||||
import org.apache.commons.math3.exception.MathArithmeticException;
|
||||
import org.apache.commons.math3.random.MersenneTwister;
|
||||
import org.apache.commons.math3.random.RandomGenerator;
|
||||
import org.apache.commons.math3.random.Well1024a;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
|
@ -958,13 +961,13 @@ public class FastMathTest {
|
|||
@Test
|
||||
public void testNextAfter() {
|
||||
// 0x402fffffffffffff 0x404123456789abcd -> 4030000000000000
|
||||
Assert.assertEquals(16.0, FastMath.nextAfter(15.999999999999998, 34.27555555555555), 0.0);
|
||||
Assert.assertEquals(16.0, FastMath.nextUp(15.999999999999998), 0.0);
|
||||
|
||||
// 0xc02fffffffffffff 0x404123456789abcd -> c02ffffffffffffe
|
||||
Assert.assertEquals(-15.999999999999996, FastMath.nextAfter(-15.999999999999998, 34.27555555555555), 0.0);
|
||||
|
||||
// 0x402fffffffffffff 0x400123456789abcd -> 402ffffffffffffe
|
||||
Assert.assertEquals(15.999999999999996, FastMath.nextAfter(15.999999999999998, 2.142222222222222), 0.0);
|
||||
Assert.assertEquals(15.999999999999996, FastMath.nextDown(15.999999999999998), 0.0);
|
||||
|
||||
// 0xc02fffffffffffff 0x400123456789abcd -> c02ffffffffffffe
|
||||
Assert.assertEquals(-15.999999999999996, FastMath.nextAfter(-15.999999999999998, 2.142222222222222), 0.0);
|
||||
|
@ -1037,8 +1040,8 @@ public class FastMathTest {
|
|||
Assert.assertEquals(-Float.MAX_VALUE,FastMath.nextAfter(Float.NEGATIVE_INFINITY, 0F), 0F);
|
||||
Assert.assertEquals(Float.MAX_VALUE,FastMath.nextAfter(Float.POSITIVE_INFINITY, 0F), 0F);
|
||||
Assert.assertEquals(Float.NaN,FastMath.nextAfter(Float.NaN, 0F), 0F);
|
||||
Assert.assertEquals(Float.POSITIVE_INFINITY,FastMath.nextAfter(Float.MAX_VALUE, Float.POSITIVE_INFINITY), 0F);
|
||||
Assert.assertEquals(Float.NEGATIVE_INFINITY,FastMath.nextAfter(-Float.MAX_VALUE, Float.NEGATIVE_INFINITY), 0F);
|
||||
Assert.assertEquals(Float.POSITIVE_INFINITY,FastMath.nextUp(Float.MAX_VALUE), 0F);
|
||||
Assert.assertEquals(Float.NEGATIVE_INFINITY,FastMath.nextDown(-Float.MAX_VALUE), 0F);
|
||||
Assert.assertEquals(Float.MIN_VALUE, FastMath.nextAfter(0F, 1F), 0F);
|
||||
Assert.assertEquals(-Float.MIN_VALUE, FastMath.nextAfter(0F, -1F), 0F);
|
||||
Assert.assertEquals(0F, FastMath.nextAfter(Float.MIN_VALUE, -1F), 0F);
|
||||
|
@ -1182,4 +1185,422 @@ public class FastMathTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncrementExactInt() {
|
||||
int[] specialValues = new int[] {
|
||||
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
|
||||
-1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
|
||||
};
|
||||
for (int a : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdSum = bdA.add(BigInteger.ONE);
|
||||
if (bdSum.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
|
||||
bdSum.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.incrementExact(a);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdSum, BigInteger.valueOf(FastMath.incrementExact(a)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecrementExactInt() {
|
||||
int[] specialValues = new int[] {
|
||||
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
|
||||
-1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
|
||||
};
|
||||
for (int a : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdSub = bdA.subtract(BigInteger.ONE);
|
||||
if (bdSub.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
|
||||
bdSub.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.decrementExact(a);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdSub, BigInteger.valueOf(FastMath.decrementExact(a)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddExactInt() {
|
||||
int[] specialValues = new int[] {
|
||||
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
|
||||
-1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
|
||||
};
|
||||
for (int a : specialValues) {
|
||||
for (int b : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdB = BigInteger.valueOf(b);
|
||||
BigInteger bdSum = bdA.add(bdB);
|
||||
if (bdSum.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
|
||||
bdSum.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.addExact(a, b);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdSum, BigInteger.valueOf(FastMath.addExact(a, b)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddExactLong() {
|
||||
long[] specialValues = new long[] {
|
||||
Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 2,
|
||||
Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Long.MIN_VALUE / 2), 0 - (Long.MIN_VALUE / 2), 1 - (Long.MIN_VALUE / 2),
|
||||
-1 + (Long.MAX_VALUE / 2), 0 + (Long.MAX_VALUE / 2), 1 + (Long.MAX_VALUE / 2),
|
||||
};
|
||||
for (long a : specialValues) {
|
||||
for (long b : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdB = BigInteger.valueOf(b);
|
||||
BigInteger bdSum = bdA.add(bdB);
|
||||
if (bdSum.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0 ||
|
||||
bdSum.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.addExact(a, b);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdSum, BigInteger.valueOf(FastMath.addExact(a, b)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubtractExactInt() {
|
||||
int[] specialValues = new int[] {
|
||||
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
|
||||
-1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
|
||||
};
|
||||
for (int a : specialValues) {
|
||||
for (int b : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdB = BigInteger.valueOf(b);
|
||||
BigInteger bdSub = bdA.subtract(bdB);
|
||||
if (bdSub.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
|
||||
bdSub.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.subtractExact(a, b);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdSub, BigInteger.valueOf(FastMath.subtractExact(a, b)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubtractExactLong() {
|
||||
long[] specialValues = new long[] {
|
||||
Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 2,
|
||||
Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Long.MIN_VALUE / 2), 0 - (Long.MIN_VALUE / 2), 1 - (Long.MIN_VALUE / 2),
|
||||
-1 + (Long.MAX_VALUE / 2), 0 + (Long.MAX_VALUE / 2), 1 + (Long.MAX_VALUE / 2),
|
||||
};
|
||||
for (long a : specialValues) {
|
||||
for (long b : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdB = BigInteger.valueOf(b);
|
||||
BigInteger bdSub = bdA.subtract(bdB);
|
||||
if (bdSub.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0 ||
|
||||
bdSub.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.subtractExact(a, b);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdSub, BigInteger.valueOf(FastMath.subtractExact(a, b)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplyExactInt() {
|
||||
int[] specialValues = new int[] {
|
||||
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
|
||||
-1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
|
||||
};
|
||||
for (int a : specialValues) {
|
||||
for (int b : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdB = BigInteger.valueOf(b);
|
||||
BigInteger bdMul = bdA.multiply(bdB);
|
||||
if (bdMul.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
|
||||
bdMul.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.multiplyExact(a, b);
|
||||
Assert.fail("an exception should have been thrown " + a + b);
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdMul, BigInteger.valueOf(FastMath.multiplyExact(a, b)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplyExactLong() {
|
||||
long[] specialValues = new long[] {
|
||||
Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 2,
|
||||
Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 2,
|
||||
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
-1 - (Long.MIN_VALUE / 2), 0 - (Long.MIN_VALUE / 2), 1 - (Long.MIN_VALUE / 2),
|
||||
-1 + (Long.MAX_VALUE / 2), 0 + (Long.MAX_VALUE / 2), 1 + (Long.MAX_VALUE / 2),
|
||||
};
|
||||
for (long a : specialValues) {
|
||||
for (long b : specialValues) {
|
||||
BigInteger bdA = BigInteger.valueOf(a);
|
||||
BigInteger bdB = BigInteger.valueOf(b);
|
||||
BigInteger bdMul = bdA.multiply(bdB);
|
||||
if (bdMul.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0 ||
|
||||
bdMul.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
|
||||
try {
|
||||
FastMath.multiplyExact(a, b);
|
||||
Assert.fail("an exception should have been thrown " + a + b);
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals(bdMul, BigInteger.valueOf(FastMath.multiplyExact(a, b)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=MathArithmeticException.class)
|
||||
public void testToIntExactTooLow() {
|
||||
FastMath.toIntExact(-1l + Integer.MIN_VALUE);
|
||||
}
|
||||
|
||||
@Test(expected=MathArithmeticException.class)
|
||||
public void testToIntExactTooHigh() {
|
||||
FastMath.toIntExact(+1l + Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToIntExact() {
|
||||
for (int n = -1000; n < 1000; ++n) {
|
||||
Assert.assertEquals(n, FastMath.toIntExact(0l + n));
|
||||
}
|
||||
Assert.assertEquals(Integer.MIN_VALUE, FastMath.toIntExact(0l + Integer.MIN_VALUE));
|
||||
Assert.assertEquals(Integer.MAX_VALUE, FastMath.toIntExact(0l + Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloorDivInt() {
|
||||
Assert.assertEquals(+1, FastMath.floorDiv(+4, +3));
|
||||
Assert.assertEquals(-2, FastMath.floorDiv(-4, +3));
|
||||
Assert.assertEquals(-2, FastMath.floorDiv(+4, -3));
|
||||
Assert.assertEquals(+1, FastMath.floorDiv(-4, -3));
|
||||
try {
|
||||
FastMath.floorDiv(1, 0);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
for (int a = -100; a <= 100; ++a) {
|
||||
for (int b = -100; b <= 100; ++b) {
|
||||
if (b != 0) {
|
||||
Assert.assertEquals(poorManFloorDiv(a, b), FastMath.floorDiv(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloorModInt() {
|
||||
Assert.assertEquals(+1, FastMath.floorMod(+4, +3));
|
||||
Assert.assertEquals(+2, FastMath.floorMod(-4, +3));
|
||||
Assert.assertEquals(-2, FastMath.floorMod(+4, -3));
|
||||
Assert.assertEquals(-1, FastMath.floorMod(-4, -3));
|
||||
try {
|
||||
FastMath.floorMod(1, 0);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
for (int a = -100; a <= 100; ++a) {
|
||||
for (int b = -100; b <= 100; ++b) {
|
||||
if (b != 0) {
|
||||
Assert.assertEquals(poorManFloorMod(a, b), FastMath.floorMod(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloorDivModInt() {
|
||||
RandomGenerator generator = new Well1024a(0x7ccab45edeaab90al);
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
int a = generator.nextInt();
|
||||
int b = generator.nextInt();
|
||||
if (b == 0) {
|
||||
try {
|
||||
FastMath.floorDiv(a, b);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
int d = FastMath.floorDiv(a, b);
|
||||
int m = FastMath.floorMod(a, b);
|
||||
Assert.assertEquals(FastMath.toIntExact(poorManFloorDiv(a, b)), d);
|
||||
Assert.assertEquals(FastMath.toIntExact(poorManFloorMod(a, b)), m);
|
||||
Assert.assertEquals(a, d * b + m);
|
||||
if (b < 0) {
|
||||
Assert.assertTrue(m <= 0);
|
||||
Assert.assertTrue(-m < -b);
|
||||
} else {
|
||||
Assert.assertTrue(m >= 0);
|
||||
Assert.assertTrue(m < b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloorDivLong() {
|
||||
Assert.assertEquals(+1l, FastMath.floorDiv(+4l, +3l));
|
||||
Assert.assertEquals(-2l, FastMath.floorDiv(-4l, +3l));
|
||||
Assert.assertEquals(-2l, FastMath.floorDiv(+4l, -3l));
|
||||
Assert.assertEquals(+1l, FastMath.floorDiv(-4l, -3l));
|
||||
try {
|
||||
FastMath.floorDiv(1l, 0l);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
for (long a = -100l; a <= 100l; ++a) {
|
||||
for (long b = -100l; b <= 100l; ++b) {
|
||||
if (b != 0) {
|
||||
Assert.assertEquals(poorManFloorDiv(a, b), FastMath.floorDiv(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloorModLong() {
|
||||
Assert.assertEquals(+1l, FastMath.floorMod(+4l, +3l));
|
||||
Assert.assertEquals(+2l, FastMath.floorMod(-4l, +3l));
|
||||
Assert.assertEquals(-2l, FastMath.floorMod(+4l, -3l));
|
||||
Assert.assertEquals(-1l, FastMath.floorMod(-4l, -3l));
|
||||
try {
|
||||
FastMath.floorMod(1l, 0l);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
for (long a = -100l; a <= 100l; ++a) {
|
||||
for (long b = -100l; b <= 100l; ++b) {
|
||||
if (b != 0) {
|
||||
Assert.assertEquals(poorManFloorMod(a, b), FastMath.floorMod(a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloorDivModLong() {
|
||||
RandomGenerator generator = new Well1024a(0xb87b9bc14c96ccd5l);
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
long a = generator.nextLong();
|
||||
long b = generator.nextLong();
|
||||
if (b == 0) {
|
||||
try {
|
||||
FastMath.floorDiv(a, b);
|
||||
Assert.fail("an exception should have been thrown");
|
||||
} catch (MathArithmeticException mae) {
|
||||
// expected
|
||||
}
|
||||
} else {
|
||||
long d = FastMath.floorDiv(a, b);
|
||||
long m = FastMath.floorMod(a, b);
|
||||
Assert.assertEquals(poorManFloorDiv(a, b), d);
|
||||
Assert.assertEquals(poorManFloorMod(a, b), m);
|
||||
Assert.assertEquals(a, d * b + m);
|
||||
if (b < 0) {
|
||||
Assert.assertTrue(m <= 0);
|
||||
Assert.assertTrue(-m < -b);
|
||||
} else {
|
||||
Assert.assertTrue(m >= 0);
|
||||
Assert.assertTrue(m < b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long poorManFloorDiv(long a, long b) {
|
||||
|
||||
// find q0, r0 such that a = q0 b + r0
|
||||
BigInteger q0 = BigInteger.valueOf(a / b);
|
||||
BigInteger r0 = BigInteger.valueOf(a % b);
|
||||
BigInteger fd = BigInteger.valueOf(Integer.MIN_VALUE);
|
||||
BigInteger bigB = BigInteger.valueOf(b);
|
||||
|
||||
for (int k = -2; k < 2; ++k) {
|
||||
// find another pair q, r such that a = q b + r
|
||||
BigInteger bigK = BigInteger.valueOf(k);
|
||||
BigInteger q = q0.subtract(bigK);
|
||||
BigInteger r = r0.add(bigK.multiply(bigB));
|
||||
if (r.abs().compareTo(bigB.abs()) < 0 &&
|
||||
(r.longValue() == 0l || ((r.longValue() ^ b) & 0x8000000000000000l) == 0)) {
|
||||
if (fd.compareTo(q) < 0) {
|
||||
fd = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fd.longValue();
|
||||
|
||||
}
|
||||
|
||||
private long poorManFloorMod(long a, long b) {
|
||||
return a - b * poorManFloorDiv(a, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue