8229485: Add decrementExact(), incrementExact(), and negateExact() to java.lang.StrictMath

Three methods are added to StrictMath for consistency with Math. Tests are updated accordingly.

Reviewed-by: bpb, lancea, igerasim, dfuchs, joehw, rriggs
This commit is contained in:
Julia Boes 2019-08-23 19:55:08 +01:00 committed by Daniel Fuchs
parent ed17c3aafb
commit ce3face998
3 changed files with 184 additions and 31 deletions

View File

@ -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 @@ import jdk.internal.HotSpotIntrinsicCandidate;
* 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 @@ public final class StrictMath {
}
/**
* 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

View File

@ -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 @@ public class ExactArithTests {
}
/**
* 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 @@ public class ExactArithTests {
testIntegerExact(Integer.MAX_VALUE, -1);
testIntegerExact(Integer.MIN_VALUE, -2);
testIntegerExact(Integer.MAX_VALUE, -2);
}
/**
@ -101,7 +100,6 @@ public class ExactArithTests {
long sum2 = (long) x + (long) y;
if ((int) sum2 == sum2) {
fail("FAIL: int Math.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
}
}
@ -147,7 +145,6 @@ public class ExactArithTests {
long inc2 = (long) x + 1L;
if ((int) inc2 == inc2) {
fail("FAIL: int Math.incrementExact(" + x + ")" + "; Unexpected exception: " + ex);
}
}
@ -164,31 +161,29 @@ public class ExactArithTests {
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 @@ public class ExactArithTests {
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 @@ public class ExactArithTests {
fail("FAIL: long Math.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
}
}
}
/**

View File

@ -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 @@ public class ExactArithTests {
}
/**
* 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 @@ public class ExactArithTests {
testIntegerExact(Integer.MAX_VALUE, -1);
testIntegerExact(Integer.MIN_VALUE, -2);
testIntegerExact(Integer.MAX_VALUE, -2);
}
/**
@ -100,7 +99,6 @@ public class ExactArithTests {
long sum2 = (long) x + (long) y;
if ((int) sum2 == sum2) {
fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
}
}
@ -133,11 +131,58 @@ public class ExactArithTests {
}
}
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 @@ public class ExactArithTests {
testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
testLongExactTwice(Integer.MIN_VALUE/2, 2);
}
/**
@ -224,6 +268,39 @@ public class ExactArithTests {
}
}
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);
@ -235,7 +312,6 @@ public class ExactArithTests {
fail("FAIL: long StrictMath.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
}
}
}
/**