mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-24 12:28:12 +00:00
6708398: Support integer overflow
Added add/sub/multiply/toIntExact methods to j.l.Math and StrictMath classes Reviewed-by: emcmanus
This commit is contained in:
parent
4c5ba0d841
commit
ac69a5f84a
@ -81,6 +81,22 @@ import sun.misc.DoubleConsts;
|
||||
* floating-point approximation. Not all approximations that have 1
|
||||
* ulp accuracy will automatically meet the monotonicity requirements.
|
||||
*
|
||||
* <p>
|
||||
* The platform uses signed two's complement integer arithmetic with
|
||||
* int and long primitive types. The developer should choose
|
||||
* the primitive type to ensure that arithmetic operations consistently
|
||||
* produce correct results, which in some cases means the operations
|
||||
* will not overflow the range of values of the computation.
|
||||
* The best practice is to choose the primitive type and algorithm to avoid
|
||||
* overflow. In cases where the size is {@code int} or {@code long} and
|
||||
* overflow errors need to be detected, the methods {@code addExact},
|
||||
* {@code subtractExact}, {@code multiplyExact}, and {@code toIntExact}
|
||||
* throw an {@code ArithmeticException} when the results overflow.
|
||||
* For other arithmetic operations such as divide, absolute value,
|
||||
* increment, decrement, and negation overflow occurs only with
|
||||
* a specific minimum or maximum value and should be checked against
|
||||
* the minimum or maximum as appropriate.
|
||||
*
|
||||
* @author unascribed
|
||||
* @author Joseph D. Darcy
|
||||
* @since JDK1.0
|
||||
@ -718,6 +734,137 @@ public final class Math {
|
||||
return rnd.nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of its arguments,
|
||||
* throwing an exception if the result overflows an {@code int}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows an int
|
||||
*/
|
||||
public static int addExact(int x, int y) {
|
||||
int r = x + y;
|
||||
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
|
||||
if (((x ^ r) & (y ^ r)) < 0) {
|
||||
throw new ArithmeticException("integer overflow");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of its arguments,
|
||||
* throwing an exception if the result overflows a {@code long}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows a long
|
||||
*/
|
||||
public static long addExact(long x, long y) {
|
||||
long r = x + y;
|
||||
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
|
||||
if (((x ^ r) & (y ^ r)) < 0) {
|
||||
throw new ArithmeticException("long overflow");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the difference of the arguments,
|
||||
* throwing an exception if the result overflows an {@code int}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value to subtract from the first
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows an int
|
||||
*/
|
||||
public static int subtractExact(int x, int y) {
|
||||
int r = x - y;
|
||||
// HD 2-12 Overflow iff the arguments have different signs and
|
||||
// the sign of the result is different than the sign of x
|
||||
if (((x ^ y) & (x ^ r)) < 0) {
|
||||
throw new ArithmeticException("integer overflow");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the difference of the arguments,
|
||||
* throwing an exception if the result overflows a {@code long}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value to subtract from the first
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows a long
|
||||
*/
|
||||
public static long subtractExact(long x, long y) {
|
||||
long r = x - y;
|
||||
// HD 2-12 Overflow iff the arguments have different signs and
|
||||
// the sign of the result is different than the sign of x
|
||||
if (((x ^ y) & (x ^ r)) < 0) {
|
||||
throw new ArithmeticException("long overflow");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product of the arguments,
|
||||
* throwing an exception if the result overflows an {@code int}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows an int
|
||||
*/
|
||||
public static int multiplyExact(int x, int y) {
|
||||
long r = (long)x * (long)y;
|
||||
if ((int)r != r) {
|
||||
throw new ArithmeticException("long overflow");
|
||||
}
|
||||
return (int)r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product of the arguments,
|
||||
* throwing an exception if the result overflows a {@code long}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows a long
|
||||
*/
|
||||
public static long multiplyExact(long x, long y) {
|
||||
long r = x * y;
|
||||
long ax = Math.abs(x);
|
||||
long ay = Math.abs(y);
|
||||
if (((ax | ay) >>> 31 != 0)) {
|
||||
// Some bits greater than 2^31 that might cause overflow
|
||||
// Check the result using the divide operator
|
||||
// and check for the special case of Long.MIN_VALUE * -1
|
||||
if (((y != 0) && (r / y != x)) ||
|
||||
(x == Long.MIN_VALUE && y == -1)) {
|
||||
throw new ArithmeticException("long overflow");
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code long} argument;
|
||||
* throwing an exception if the value overflows an {@code int}.
|
||||
*
|
||||
* @param value the long value
|
||||
* @return the argument as an int
|
||||
* @throws ArithmeticException if the {@code argument} overflows an int
|
||||
*/
|
||||
public static int toIntExact(long value) {
|
||||
if ((int)value != value) {
|
||||
throw new ArithmeticException("integer overflow");
|
||||
}
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value of an {@code int} value.
|
||||
* If the argument is not negative, the argument is returned.
|
||||
@ -1737,7 +1884,7 @@ public final class Math {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code d} ×
|
||||
* Returns {@code d} ×
|
||||
* 2<sup>{@code scaleFactor}</sup> rounded as if performed
|
||||
* by a single correctly rounded floating-point multiply to a
|
||||
* member of the double value set. See the Java
|
||||
@ -1844,7 +1991,7 @@ public final class Math {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code f} ×
|
||||
* Returns {@code f} ×
|
||||
* 2<sup>{@code scaleFactor}</sup> rounded as if performed
|
||||
* by a single correctly rounded floating-point multiply to a
|
||||
* member of the float value set. See the Java
|
||||
|
||||
@ -56,6 +56,22 @@ import sun.misc.DoubleConsts;
|
||||
* {@code sinh}, {@code cosh}, {@code tanh},
|
||||
* {@code hypot}, {@code expm1}, and {@code log1p}.
|
||||
*
|
||||
* <p>
|
||||
* The platform uses signed two's complement integer arithmetic with
|
||||
* int and long primitive types. The developer should choose
|
||||
* the primitive type to ensure that arithmetic operations consistently
|
||||
* produce correct results, which in some cases means the operations
|
||||
* will not overflow the range of values of the computation.
|
||||
* The best practice is to choose the primitive type and algorithm to avoid
|
||||
* overflow. In cases where the size is {@code int} or {@code long} and
|
||||
* overflow errors need to be detected, the methods {@code addExact},
|
||||
* {@code subtractExact}, {@code multiplyExact}, and {@code toIntExact}
|
||||
* throw an {@code ArithmeticException} when the results overflow.
|
||||
* For other arithmetic operations such as divide, absolute value,
|
||||
* increment, decrement, and negation overflow occurs only with
|
||||
* a specific minimum or maximum value and should be checked against
|
||||
* the minimum or maximum as appropriate.
|
||||
*
|
||||
* @author unascribed
|
||||
* @author Joseph D. Darcy
|
||||
* @since 1.3
|
||||
@ -699,7 +715,111 @@ public final class StrictMath {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value of an {@code int} value..
|
||||
* Returns the sum of its arguments,
|
||||
* throwing an exception if the result overflows an {@code int}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows an int
|
||||
* @see Math#addExact(int,int)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static int addExact(int x, int y) {
|
||||
return Math.addExact(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of its arguments,
|
||||
* throwing an exception if the result overflows a {@code long}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows a long
|
||||
* @see Math#addExact(long,long)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static long addExact(long x, long y) {
|
||||
return Math.addExact(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the difference of the arguments,
|
||||
* throwing an exception if the result overflows an {@code int}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value to subtract from the first
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows an int
|
||||
* @see Math#subtractExact(int,int)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static int subtractExact(int x, int y) {
|
||||
return Math.subtractExact(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the difference of the arguments,
|
||||
* throwing an exception if the result overflows a {@code long}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value to subtract from the first
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows a long
|
||||
* @see Math#subtractExact(long,long)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static long subtractExact(long x, long y) {
|
||||
return Math.subtractExact(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the product of the arguments,
|
||||
* throwing an exception if the result overflows an {@code int}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows an int
|
||||
* @see Math#multiplyExact(int,int)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static int multiplyExact(int x, int y) {
|
||||
return Math.multiplyExact(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the product of the arguments,
|
||||
* throwing an exception if the result overflows a {@code long}.
|
||||
*
|
||||
* @param x the first value
|
||||
* @param y the second value
|
||||
* @return the result
|
||||
* @throws ArithmeticException if the result overflows a long
|
||||
* @see Math#multiplyExact(long,long)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static long multiplyExact(long x, long y) {
|
||||
return Math.multiplyExact(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the {@code long} argument;
|
||||
* throwing an exception if the value overflows an {@code int}.
|
||||
*
|
||||
* @param value the long value
|
||||
* @return the argument as an int
|
||||
* @throws ArithmeticException if the {@code argument} overflows an int
|
||||
* @see Math#toIntExact(int)
|
||||
* @since 1.8
|
||||
*/
|
||||
public static int toIntExact(long value) {
|
||||
return Math.toIntExact(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value of an {@code int} value.
|
||||
* If the argument is not negative, the argument is returned.
|
||||
* If the argument is negative, the negation of the argument is returned.
|
||||
*
|
||||
|
||||
266
jdk/test/java/lang/Math/ExactArithTests.java
Normal file
266
jdk/test/java/lang/Math/ExactArithTests.java
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @test Test for Math.*Exact integer and long methods.
|
||||
* @bug 6708398
|
||||
* @summary Basic tests for Math exact arithmetic operations.
|
||||
*
|
||||
* @author Roger Riggs
|
||||
*/
|
||||
public class ExactArithTests {
|
||||
|
||||
/**
|
||||
* The count of test errors.
|
||||
*/
|
||||
private static int errors = 0;
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
testIntegerExact();
|
||||
testLongExact();
|
||||
|
||||
if (errors > 0) {
|
||||
throw new RuntimeException(errors + " errors found in ExactArithTests.");
|
||||
}
|
||||
}
|
||||
|
||||
static void fail(String message) {
|
||||
errors++;
|
||||
System.err.println(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Math.addExact, multiplyExact, subtractExact, toIntValue methods
|
||||
* with {@code int} arguments.
|
||||
*/
|
||||
static void testIntegerExact() {
|
||||
testIntegerExact(0, 0);
|
||||
testIntegerExact(1, 1);
|
||||
testIntegerExact(1, -1);
|
||||
testIntegerExact(-1, 1);
|
||||
testIntegerExact(1000, 2000);
|
||||
|
||||
testIntegerExact(Integer.MIN_VALUE, Integer.MIN_VALUE);
|
||||
testIntegerExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
testIntegerExact(Integer.MIN_VALUE, 1);
|
||||
testIntegerExact(Integer.MAX_VALUE, 1);
|
||||
testIntegerExact(Integer.MIN_VALUE, 2);
|
||||
testIntegerExact(Integer.MAX_VALUE, 2);
|
||||
testIntegerExact(Integer.MIN_VALUE, -1);
|
||||
testIntegerExact(Integer.MAX_VALUE, -1);
|
||||
testIntegerExact(Integer.MIN_VALUE, -2);
|
||||
testIntegerExact(Integer.MAX_VALUE, -2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exact arithmetic by comparing with the same operations using long
|
||||
* and checking that the result is the same as the integer truncation.
|
||||
* Errors are reported with {@link fail}.
|
||||
*
|
||||
* @param x first parameter
|
||||
* @param y second parameter
|
||||
*/
|
||||
static void testIntegerExact(int x, int y) {
|
||||
try {
|
||||
// Test addExact
|
||||
int sum = Math.addExact(x, y);
|
||||
long sum2 = (long) x + (long) y;
|
||||
if ((int) sum2 != sum2) {
|
||||
fail("FAIL: int Math.addExact(" + x + " + " + y + ") = " + sum + "; expected Arithmetic exception");
|
||||
} else if (sum != sum2) {
|
||||
fail("FAIL: long Math.addExact(" + x + " + " + y + ") = " + sum + "; expected: " + sum2);
|
||||
}
|
||||
} catch (ArithmeticException ex) {
|
||||
long sum2 = (long) x + (long) y;
|
||||
if ((int) sum2 == sum2) {
|
||||
fail("FAIL: int Math.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test subtractExact
|
||||
int diff = Math.subtractExact(x, y);
|
||||
long diff2 = (long) x - (long) y;
|
||||
if ((int) diff2 != diff2) {
|
||||
fail("FAIL: int Math.subtractExact(" + x + " - " + y + ") = " + diff + "; expected: " + diff2);
|
||||
}
|
||||
|
||||
} catch (ArithmeticException ex) {
|
||||
long diff2 = (long) x - (long) y;
|
||||
if ((int) diff2 == diff2) {
|
||||
fail("FAIL: int Math.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test multiplyExact
|
||||
int product = Math.multiplyExact(x, y);
|
||||
long m2 = (long) x * (long) y;
|
||||
if ((int) m2 != m2) {
|
||||
fail("FAIL: int Math.multiplyExact(" + x + " * " + y + ") = " + product + "; expected: " + m2);
|
||||
}
|
||||
} catch (ArithmeticException ex) {
|
||||
long m2 = (long) x * (long) y;
|
||||
if ((int) m2 == m2) {
|
||||
fail("FAIL: int Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Math.addExact, multiplyExact, subtractExact, toIntExact methods
|
||||
* with {@code long} arguments.
|
||||
*/
|
||||
static void testLongExact() {
|
||||
testLongExactTwice(0, 0);
|
||||
testLongExactTwice(1, 1);
|
||||
testLongExactTwice(1, -1);
|
||||
testLongExactTwice(1000, 2000);
|
||||
|
||||
testLongExactTwice(Long.MIN_VALUE, Long.MIN_VALUE);
|
||||
testLongExactTwice(Long.MAX_VALUE, Long.MAX_VALUE);
|
||||
testLongExactTwice(Long.MIN_VALUE, 1);
|
||||
testLongExactTwice(Long.MAX_VALUE, 1);
|
||||
testLongExactTwice(Long.MIN_VALUE, 2);
|
||||
testLongExactTwice(Long.MAX_VALUE, 2);
|
||||
testLongExactTwice(Long.MIN_VALUE, -1);
|
||||
testLongExactTwice(Long.MAX_VALUE, -1);
|
||||
testLongExactTwice(Long.MIN_VALUE, -2);
|
||||
testLongExactTwice(Long.MAX_VALUE, -2);
|
||||
testLongExactTwice(Long.MIN_VALUE/2, 2);
|
||||
testLongExactTwice(Long.MAX_VALUE, 2);
|
||||
testLongExactTwice(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
testLongExactTwice(Integer.MAX_VALUE, -Integer.MAX_VALUE);
|
||||
testLongExactTwice(Integer.MAX_VALUE+1, Integer.MAX_VALUE+1);
|
||||
testLongExactTwice(Integer.MAX_VALUE+1, -Integer.MAX_VALUE+1);
|
||||
testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
|
||||
testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
|
||||
testLongExactTwice(Integer.MIN_VALUE/2, 2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test each of the exact operations with the arguments and
|
||||
* with the arguments reversed.
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
static void testLongExactTwice(long x, long y) {
|
||||
testLongExact(x, y);
|
||||
testLongExact(y, x);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test long exact arithmetic by comparing with the same operations using BigInteger
|
||||
* and checking that the result is the same as the long truncation.
|
||||
* Errors are reported with {@link fail}.
|
||||
*
|
||||
* @param x first parameter
|
||||
* @param y second parameter
|
||||
*/
|
||||
static void testLongExact(long x, long y) {
|
||||
BigInteger resultBig = null;
|
||||
final BigInteger xBig = BigInteger.valueOf(x);
|
||||
final BigInteger yBig = BigInteger.valueOf(y);
|
||||
try {
|
||||
// Test addExact
|
||||
resultBig = xBig.add(yBig);
|
||||
long sum = Math.addExact(x, y);
|
||||
checkResult("long Math.addExact", x, y, sum, resultBig);
|
||||
} catch (ArithmeticException ex) {
|
||||
if (inLongRange(resultBig)) {
|
||||
fail("FAIL: long Math.addExact(" + x + " + " + y + "); Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test subtractExact
|
||||
resultBig = xBig.subtract(yBig);
|
||||
long diff = Math.subtractExact(x, y);
|
||||
checkResult("long Math.subtractExact", x, y, diff, resultBig);
|
||||
} catch (ArithmeticException ex) {
|
||||
if (inLongRange(resultBig)) {
|
||||
fail("FAIL: long Math.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test multiplyExact
|
||||
resultBig = xBig.multiply(yBig);
|
||||
long product = Math.multiplyExact(x, y);
|
||||
checkResult("long Math.multiplyExact", x, y, product, resultBig);
|
||||
} catch (ArithmeticException ex) {
|
||||
if (inLongRange(resultBig)) {
|
||||
fail("FAIL: long Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test toIntExact
|
||||
int value = Math.toIntExact(x);
|
||||
if ((long)value != x) {
|
||||
fail("FAIL: " + "long Math.toIntExact" + "(" + x + ") = " + value + "; expected an arithmetic exception: ");
|
||||
}
|
||||
} catch (ArithmeticException ex) {
|
||||
if (resultBig.bitLength() <= 32) {
|
||||
fail("FAIL: long Math.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the expected and actual results.
|
||||
* @param message message for the error
|
||||
* @param x first argument
|
||||
* @param y second argument
|
||||
* @param result actual result value
|
||||
* @param expected expected result value
|
||||
*/
|
||||
static void checkResult(String message, long x, long y, long result, BigInteger expected) {
|
||||
BigInteger resultBig = BigInteger.valueOf(result);
|
||||
if (!inLongRange(expected)) {
|
||||
fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected an arithmetic exception: ");
|
||||
} else if (!resultBig.equals(expected)) {
|
||||
fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected " + expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the value fits in 64 bits (a long).
|
||||
* @param value
|
||||
* @return true if the value fits in 64 bits (including the sign).
|
||||
*/
|
||||
static boolean inLongRange(BigInteger value) {
|
||||
return value.bitLength() <= 63;
|
||||
}
|
||||
}
|
||||
266
jdk/test/java/lang/StrictMath/ExactArithTests.java
Normal file
266
jdk/test/java/lang/StrictMath/ExactArithTests.java
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @test Test for StrictMath.*Exact integer and long methods.
|
||||
* @bug 6708398
|
||||
* @summary Basic tests for StrictMath exact arithmetic operations.
|
||||
*
|
||||
* @author Roger Riggs
|
||||
*/
|
||||
public class ExactArithTests {
|
||||
|
||||
/**
|
||||
* The count of test errors.
|
||||
*/
|
||||
private static int errors = 0;
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
testIntegerExact();
|
||||
testLongExact();
|
||||
|
||||
if (errors > 0) {
|
||||
throw new RuntimeException(errors + " errors found in ExactArithTests.");
|
||||
}
|
||||
}
|
||||
|
||||
static void fail(String message) {
|
||||
errors++;
|
||||
System.err.println(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test StrictMath.addExact, multiplyExact, subtractExact, toIntValue methods
|
||||
* with {@code int} arguments.
|
||||
*/
|
||||
static void testIntegerExact() {
|
||||
testIntegerExact(0, 0);
|
||||
testIntegerExact(1, 1);
|
||||
testIntegerExact(1, -1);
|
||||
testIntegerExact(-1, 1);
|
||||
testIntegerExact(1000, 2000);
|
||||
|
||||
testIntegerExact(Integer.MIN_VALUE, Integer.MIN_VALUE);
|
||||
testIntegerExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
testIntegerExact(Integer.MIN_VALUE, 1);
|
||||
testIntegerExact(Integer.MAX_VALUE, 1);
|
||||
testIntegerExact(Integer.MIN_VALUE, 2);
|
||||
testIntegerExact(Integer.MAX_VALUE, 2);
|
||||
testIntegerExact(Integer.MIN_VALUE, -1);
|
||||
testIntegerExact(Integer.MAX_VALUE, -1);
|
||||
testIntegerExact(Integer.MIN_VALUE, -2);
|
||||
testIntegerExact(Integer.MAX_VALUE, -2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exact arithmetic by comparing with the same operations using long
|
||||
* and checking that the result is the same as the integer truncation.
|
||||
* Errors are reported with {@link fail}.
|
||||
*
|
||||
* @param x first parameter
|
||||
* @param y second parameter
|
||||
*/
|
||||
static void testIntegerExact(int x, int y) {
|
||||
try {
|
||||
// Test addExact
|
||||
int sum = StrictMath.addExact(x, y);
|
||||
long sum2 = (long) x + (long) y;
|
||||
if ((int) sum2 != sum2) {
|
||||
fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ") = " + sum + "; expected Arithmetic exception");
|
||||
} else if (sum != sum2) {
|
||||
fail("FAIL: long StrictMath.addExact(" + x + " + " + y + ") = " + sum + "; expected: " + sum2);
|
||||
}
|
||||
} catch (ArithmeticException ex) {
|
||||
long sum2 = (long) x + (long) y;
|
||||
if ((int) sum2 == sum2) {
|
||||
fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test subtractExact
|
||||
int diff = StrictMath.subtractExact(x, y);
|
||||
long diff2 = (long) x - (long) y;
|
||||
if ((int) diff2 != diff2) {
|
||||
fail("FAIL: int StrictMath.subtractExact(" + x + " - " + y + ") = " + diff + "; expected: " + diff2);
|
||||
}
|
||||
|
||||
} catch (ArithmeticException ex) {
|
||||
long diff2 = (long) x - (long) y;
|
||||
if ((int) diff2 == diff2) {
|
||||
fail("FAIL: int StrictMath.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test multiplyExact
|
||||
int product = StrictMath.multiplyExact(x, y);
|
||||
long m2 = (long) x * (long) y;
|
||||
if ((int) m2 != m2) {
|
||||
fail("FAIL: int StrictMath.multiplyExact(" + x + " * " + y + ") = " + product + "; expected: " + m2);
|
||||
}
|
||||
} catch (ArithmeticException ex) {
|
||||
long m2 = (long) x * (long) y;
|
||||
if ((int) m2 == m2) {
|
||||
fail("FAIL: int StrictMath.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test StrictMath.addExact, multiplyExact, subtractExact, toIntExact methods
|
||||
* with {@code long} arguments.
|
||||
*/
|
||||
static void testLongExact() {
|
||||
testLongExactTwice(0, 0);
|
||||
testLongExactTwice(1, 1);
|
||||
testLongExactTwice(1, -1);
|
||||
testLongExactTwice(1000, 2000);
|
||||
|
||||
testLongExactTwice(Long.MIN_VALUE, Long.MIN_VALUE);
|
||||
testLongExactTwice(Long.MAX_VALUE, Long.MAX_VALUE);
|
||||
testLongExactTwice(Long.MIN_VALUE, 1);
|
||||
testLongExactTwice(Long.MAX_VALUE, 1);
|
||||
testLongExactTwice(Long.MIN_VALUE, 2);
|
||||
testLongExactTwice(Long.MAX_VALUE, 2);
|
||||
testLongExactTwice(Long.MIN_VALUE, -1);
|
||||
testLongExactTwice(Long.MAX_VALUE, -1);
|
||||
testLongExactTwice(Long.MIN_VALUE, -2);
|
||||
testLongExactTwice(Long.MAX_VALUE, -2);
|
||||
testLongExactTwice(Long.MIN_VALUE/2, 2);
|
||||
testLongExactTwice(Long.MAX_VALUE, 2);
|
||||
testLongExactTwice(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
testLongExactTwice(Integer.MAX_VALUE, -Integer.MAX_VALUE);
|
||||
testLongExactTwice(Integer.MAX_VALUE+1, Integer.MAX_VALUE+1);
|
||||
testLongExactTwice(Integer.MAX_VALUE+1, -Integer.MAX_VALUE+1);
|
||||
testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
|
||||
testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
|
||||
testLongExactTwice(Integer.MIN_VALUE/2, 2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test each of the exact operations with the arguments and
|
||||
* with the arguments reversed.
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
static void testLongExactTwice(long x, long y) {
|
||||
testLongExact(x, y);
|
||||
testLongExact(y, x);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test long exact arithmetic by comparing with the same operations using BigInteger
|
||||
* and checking that the result is the same as the long truncation.
|
||||
* Errors are reported with {@link fail}.
|
||||
*
|
||||
* @param x first parameter
|
||||
* @param y second parameter
|
||||
*/
|
||||
static void testLongExact(long x, long y) {
|
||||
BigInteger resultBig = null;
|
||||
final BigInteger xBig = BigInteger.valueOf(x);
|
||||
final BigInteger yBig = BigInteger.valueOf(y);
|
||||
try {
|
||||
// Test addExact
|
||||
resultBig = xBig.add(yBig);
|
||||
long sum = StrictMath.addExact(x, y);
|
||||
checkResult("long StrictMath.addExact", x, y, sum, resultBig);
|
||||
} catch (ArithmeticException ex) {
|
||||
if (inLongRange(resultBig)) {
|
||||
fail("FAIL: long StrictMath.addExact(" + x + " + " + y + "); Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test subtractExact
|
||||
resultBig = xBig.subtract(yBig);
|
||||
long diff = StrictMath.subtractExact(x, y);
|
||||
checkResult("long StrictMath.subtractExact", x, y, diff, resultBig);
|
||||
} catch (ArithmeticException ex) {
|
||||
if (inLongRange(resultBig)) {
|
||||
fail("FAIL: long StrictMath.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test multiplyExact
|
||||
resultBig = xBig.multiply(yBig);
|
||||
long product = StrictMath.multiplyExact(x, y);
|
||||
checkResult("long StrictMath.multiplyExact", x, y, product, resultBig);
|
||||
} catch (ArithmeticException ex) {
|
||||
if (inLongRange(resultBig)) {
|
||||
fail("FAIL: long StrictMath.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Test toIntExact
|
||||
int value = StrictMath.toIntExact(x);
|
||||
if ((long)value != x) {
|
||||
fail("FAIL: " + "long StrictMath.toIntExact" + "(" + x + ") = " + value + "; expected an arithmetic exception: ");
|
||||
}
|
||||
} catch (ArithmeticException ex) {
|
||||
if (resultBig.bitLength() <= 32) {
|
||||
fail("FAIL: long StrictMath.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the expected and actual results.
|
||||
* @param message message for the error
|
||||
* @param x first argument
|
||||
* @param y second argument
|
||||
* @param result actual result value
|
||||
* @param expected expected result value
|
||||
*/
|
||||
static void checkResult(String message, long x, long y, long result, BigInteger expected) {
|
||||
BigInteger resultBig = BigInteger.valueOf(result);
|
||||
if (!inLongRange(expected)) {
|
||||
fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected an arithmetic exception: ");
|
||||
} else if (!resultBig.equals(expected)) {
|
||||
fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected " + expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the value fits in 64 bits (a long).
|
||||
* @param value
|
||||
* @return true if the value fits in 64 bits (including the sign).
|
||||
*/
|
||||
static boolean inLongRange(BigInteger value) {
|
||||
return value.bitLength() <= 63;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user