8229485: Add decrementExact(), incrementExact(), and negateExact() to java.lang.StrictMath
Summary: three methods are added to StrictMath for consistency with Math. Tests are updated accordingly.
Reviewed-by: bpb, lancea, igerasim, dfuchs, joehw, rriggs
Contributed-by: Julia Boes <julia.boes@oracle.com>
--- a/src/java.base/share/classes/java/lang/StrictMath.java Fri Aug 23 14:04:38 2019 -0400
+++ b/src/java.base/share/classes/java/lang/StrictMath.java Fri Aug 23 19:55:08 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -67,12 +67,12 @@
* 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}
+ * {@code subtractExact}, {@code multiplyExact}, {@code toIntExact},
+ * {@code incrementExact}, {@code decrementExact} and {@code negateExact}
* throw an {@code ArithmeticException} when the results overflow.
- * For other arithmetic operations such as divide, absolute value,
- * increment by one, decrement by one, and negation overflow occurs only with
- * a specific minimum or maximum value and should be checked against
- * the minimum or maximum as appropriate.
+ * For the arithmetic operations divide and absolute value, 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
@@ -835,8 +835,92 @@
}
/**
- * Returns the value of the {@code long} argument;
- * throwing an exception if the value overflows an {@code int}.
+ * Returns the argument incremented by one,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param a the value to increment
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @see Math#incrementExact(int)
+ * @since 14
+ */
+ public static int incrementExact(int a) {
+ return Math.incrementExact(a);
+ }
+
+ /**
+ * Returns the argument incremented by one,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param a the value to increment
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @see Math#incrementExact(long)
+ * @since 14
+ */
+ public static long incrementExact(long a) {
+ return Math.incrementExact(a);
+ }
+
+ /**
+ * Returns the argument decremented by one,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param a the value to decrement
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @see Math#decrementExact(int)
+ * @since 14
+ */
+ public static int decrementExact(int a) {
+ return Math.decrementExact(a);
+ }
+
+ /**
+ * Returns the argument decremented by one,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param a the value to decrement
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @see Math#decrementExact(long)
+ * @since 14
+ */
+ public static long decrementExact(long a) {
+ return Math.decrementExact(a);
+ }
+
+ /**
+ * Returns the negation of the argument,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param a the value to negate
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @see Math#negateExact(int)
+ * @since 14
+ */
+ public static int negateExact(int a) {
+ return Math.negateExact(a);
+ }
+
+ /**
+ * Returns the negation of the argument,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param a the value to negate
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @see Math#negateExact(long)
+ * @since 14
+ */
+ public static long negateExact(long a) {
+ return Math.negateExact(a);
+ }
+
+ /**
+ * 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
--- a/test/jdk/java/lang/Math/ExactArithTests.java Fri Aug 23 14:04:38 2019 -0400
+++ b/test/jdk/java/lang/Math/ExactArithTests.java Fri Aug 23 19:55:08 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -56,8 +56,8 @@
}
/**
- * Test Math.addExact, multiplyExact, subtractExact, toIntValue methods
- * with {@code int} arguments.
+ * Test Math.addExact, multiplyExact, subtractExact, incrementExact,
+ * decrementExact, negateExact methods with {@code int} arguments.
*/
static void testIntegerExact() {
testIntegerExact(0, 0);
@@ -76,7 +76,6 @@
testIntegerExact(Integer.MAX_VALUE, -1);
testIntegerExact(Integer.MIN_VALUE, -2);
testIntegerExact(Integer.MAX_VALUE, -2);
-
}
/**
@@ -101,7 +100,6 @@
long sum2 = (long) x + (long) y;
if ((int) sum2 == sum2) {
fail("FAIL: int Math.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
-
}
}
@@ -147,7 +145,6 @@
long inc2 = (long) x + 1L;
if ((int) inc2 == inc2) {
fail("FAIL: int Math.incrementExact(" + x + ")" + "; Unexpected exception: " + ex);
-
}
}
@@ -164,31 +161,29 @@
long dec2 = (long) x - 1L;
if ((int) dec2 == dec2) {
fail("FAIL: int Math.decrementExact(" + x + ")" + "; Unexpected exception: " + ex);
-
}
}
try {
// Test negateExact
int neg = Math.negateExact(x);
- long neg2 = -((long)x) ;
+ long neg2 = -((long)x);
if ((int) neg2 != neg2) {
fail("FAIL: int Math.negateExact(" + x + ") = " + neg + "; expected Arithmetic exception");
} else if (neg != neg2) {
fail("FAIL: long Math.negateExact(" + x + ") = " + neg + "; expected: " + neg2);
}
} catch (ArithmeticException ex) {
- long neg2 = (long) x - 1L;
+ long neg2 = -((long)x);
if ((int) neg2 == neg2) {
fail("FAIL: int Math.negateExact(" + x + ")" + "; Unexpected exception: " + ex);
-
}
}
}
/**
- * Test Math.addExact, multiplyExact, subtractExact, toIntExact methods
- * with {@code long} arguments.
+ * Test Math.addExact, multiplyExact, subtractExact, incrementExact,
+ * decrementExact, negateExact, toIntExact methods with {@code long} arguments.
*/
static void testLongExact() {
testLongExactTwice(0, 0);
@@ -215,7 +210,6 @@
testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
testLongExactTwice(Integer.MIN_VALUE/2, 2);
-
}
/**
@@ -319,7 +313,6 @@
fail("FAIL: long Math.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
}
}
-
}
/**
--- a/test/jdk/java/lang/StrictMath/ExactArithTests.java Fri Aug 23 14:04:38 2019 -0400
+++ b/test/jdk/java/lang/StrictMath/ExactArithTests.java Fri Aug 23 19:55:08 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -55,8 +55,8 @@
}
/**
- * Test StrictMath.addExact, multiplyExact, subtractExact, toIntValue methods
- * with {@code int} arguments.
+ * Test StrictMath.addExact, multiplyExact, subtractExact, incrementExact,
+ * decrementExact, negateExact methods with {@code int} arguments.
*/
static void testIntegerExact() {
testIntegerExact(0, 0);
@@ -75,7 +75,6 @@
testIntegerExact(Integer.MAX_VALUE, -1);
testIntegerExact(Integer.MIN_VALUE, -2);
testIntegerExact(Integer.MAX_VALUE, -2);
-
}
/**
@@ -100,7 +99,6 @@
long sum2 = (long) x + (long) y;
if ((int) sum2 == sum2) {
fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
-
}
}
@@ -133,11 +131,58 @@
}
}
+ try {
+ // Test incrementExact
+ int inc = StrictMath.incrementExact(x);
+ long inc2 = (long) x + 1L;
+ if ((int) inc2 != inc2) {
+ fail("FAIL: int StrictMath.incrementExact(" + x + ") = " + inc + "; expected Arithmetic exception");
+ } else if (inc != inc2) {
+ fail("FAIL: long StrictMath.incrementExact(" + x + ") = " + inc + "; expected: " + inc2);
+ }
+ } catch (ArithmeticException ex) {
+ long inc2 = (long) x + 1L;
+ if ((int) inc2 == inc2) {
+ fail("FAIL: int StrictMath.incrementExact(" + x + ")" + "; Unexpected exception: " + ex);
+ }
+ }
+
+ try {
+ // Test decrementExact
+ int dec = StrictMath.decrementExact(x);
+ long dec2 = (long) x - 1L;
+ if ((int) dec2 != dec2) {
+ fail("FAIL: int StrictMath.decrementExact(" + x + ") = " + dec + "; expected Arithmetic exception");
+ } else if (dec != dec2) {
+ fail("FAIL: long StrictMath.decrementExact(" + x + ") = " + dec + "; expected: " + dec2);
+ }
+ } catch (ArithmeticException ex) {
+ long dec2 = (long) x - 1L;
+ if ((int) dec2 == dec2) {
+ fail("FAIL: int StrictMath.decrementExact(" + x + ")" + "; Unexpected exception: " + ex);
+ }
+ }
+
+ try {
+ // Test negateExact
+ int neg = StrictMath.negateExact(x);
+ long neg2 = -((long)x);
+ if ((int) neg2 != neg2) {
+ fail("FAIL: int StrictMath.negateExact(" + x + ") = " + neg + "; expected Arithmetic exception");
+ } else if (neg != neg2) {
+ fail("FAIL: long StrictMath.negateExact(" + x + ") = " + neg + "; expected: " + neg2);
+ }
+ } catch (ArithmeticException ex) {
+ long neg2 = -((long)x);
+ if ((int) neg2 == neg2) {
+ fail("FAIL: int StrictMath.negateExact(" + x + ")" + "; Unexpected exception: " + ex);
+ }
+ }
}
/**
- * Test StrictMath.addExact, multiplyExact, subtractExact, toIntExact methods
- * with {@code long} arguments.
+ * Test StrictMath.addExact, multiplyExact, subtractExact, incrementExact,
+ * decrementExact, negateExact, toIntExact methods with {@code long} arguments.
*/
static void testLongExact() {
testLongExactTwice(0, 0);
@@ -164,7 +209,6 @@
testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
testLongExactTwice(Integer.MIN_VALUE/2, 2);
-
}
/**
@@ -225,6 +269,39 @@
}
try {
+ // Test incrementExact
+ resultBig = xBig.add(BigInteger.ONE);
+ long inc = StrictMath.incrementExact(x);
+ checkResult("long Math.incrementExact", x, 1L, inc, resultBig);
+ } catch (ArithmeticException ex) {
+ if (inLongRange(resultBig)) {
+ fail("FAIL: long Math.incrementExact(" + x + "); Unexpected exception: " + ex);
+ }
+ }
+
+ try {
+ // Test decrementExact
+ resultBig = xBig.subtract(BigInteger.ONE);
+ long dec = StrictMath.decrementExact(x);
+ checkResult("long Math.decrementExact", x, 1L, dec, resultBig);
+ } catch (ArithmeticException ex) {
+ if (inLongRange(resultBig)) {
+ fail("FAIL: long Math.decrementExact(" + x + "); Unexpected exception: " + ex);
+ }
+ }
+
+ try {
+ // Test negateExact
+ resultBig = xBig.negate();
+ long dec = StrictMath.negateExact(x);
+ checkResult("long Math.negateExact", x, 0L, dec, resultBig);
+ } catch (ArithmeticException ex) {
+ if (inLongRange(resultBig)) {
+ fail("FAIL: long Math.negateExact(" + x + "); Unexpected exception: " + ex);
+ }
+ }
+
+ try {
// Test toIntExact
int value = StrictMath.toIntExact(x);
if ((long)value != x) {
@@ -235,7 +312,6 @@
fail("FAIL: long StrictMath.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
}
}
-
}
/**