# HG changeset patch # User dfuchs # Date 1566586508 -3600 # Node ID 36f5e20be69a447a461d47ade9ddc66943f7954d # Parent 1e85670cb9eef8669a57a00aa5421514250133c7 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 diff -r 1e85670cb9ee -r 36f5e20be69a src/java.base/share/classes/java/lang/StrictMath.java --- 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 diff -r 1e85670cb9ee -r 36f5e20be69a test/jdk/java/lang/Math/ExactArithTests.java --- 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); } } - } /** diff -r 1e85670cb9ee -r 36f5e20be69a test/jdk/java/lang/StrictMath/ExactArithTests.java --- 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); } } - } /**