changeset 58608:04b9012767e2

8241374: add Math.absExact Reviewed-by: smarks, chegar, bpb
author darcy
date Mon, 30 Mar 2020 13:49:02 -0700
parents 009b55b3219a
children 0d2adab6f048
files src/java.base/share/classes/java/lang/Math.java src/java.base/share/classes/java/lang/StrictMath.java test/jdk/java/lang/Math/AbsTests.java
diffstat 3 files changed, 269 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/Math.java	Fri Mar 27 15:28:07 2020 +0100
+++ b/src/java.base/share/classes/java/lang/Math.java	Mon Mar 30 13:49:02 2020 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2020, 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
@@ -1355,13 +1355,15 @@
      * If the argument is not negative, the argument is returned.
      * If the argument is negative, the negation of the argument is returned.
      *
-     * <p>Note that if the argument is equal to the value of
-     * {@link Integer#MIN_VALUE}, the most negative representable
-     * {@code int} value, the result is that same value, which is
-     * negative.
+     * <p>Note that if the argument is equal to the value of {@link
+     * Integer#MIN_VALUE}, the most negative representable {@code int}
+     * value, the result is that same value, which is negative. In
+     * contrast, the {@link Math#absExact(int)} method throws an
+     * {@code ArithmeticException} for this value.
      *
      * @param   a   the argument whose absolute value is to be determined
      * @return  the absolute value of the argument.
+     * @see Math#absExact(int)
      */
     @HotSpotIntrinsicCandidate
     public static int abs(int a) {
@@ -1369,17 +1371,45 @@
     }
 
     /**
+     * Returns the mathematical absolute value of an {@code int} value
+     * if it is exactly representable as an {@code int}, throwing
+     * {@code ArithmeticException} if the result overflows the
+     * positive {@code int} range.
+     *
+     * <p>Since the range of two's complement integers is asymmetric
+     * with one additional negative value (JLS {@jls 4.2.1}), the
+     * mathematical absolute value of {@link Integer#MIN_VALUE}
+     * overflows the positive {@code int} range, so an exception is
+     * thrown for that argument.
+     *
+     * @param  a  the argument whose absolute value is to be determined
+     * @return the absolute value of the argument, unless overflow occurs
+     * @throws ArithmeticException if the argument is {@link Integer#MIN_VALUE}
+     * @see Math#abs(int)
+     * @since 15
+     */
+    public static int absExact(int a) {
+        if (a == Integer.MIN_VALUE)
+            throw new ArithmeticException(
+                "Overflow to represent absolute value of Integer.MIN_VALUE");
+        else
+            return abs(a);
+    }
+
+    /**
      * Returns the absolute value of a {@code long} value.
      * If the argument is not negative, the argument is returned.
      * If the argument is negative, the negation of the argument is returned.
      *
-     * <p>Note that if the argument is equal to the value of
-     * {@link Long#MIN_VALUE}, the most negative representable
-     * {@code long} value, the result is that same value, which
-     * is negative.
+     * <p>Note that if the argument is equal to the value of {@link
+     * Long#MIN_VALUE}, the most negative representable {@code long}
+     * value, the result is that same value, which is negative. In
+     * contrast, the {@link Math#absExact(long)} method throws an
+     * {@code ArithmeticException} for this value.
      *
      * @param   a   the argument whose absolute value is to be determined
      * @return  the absolute value of the argument.
+     * @see Math#absExact(long)
      */
     @HotSpotIntrinsicCandidate
     public static long abs(long a) {
@@ -1387,6 +1417,32 @@
     }
 
     /**
+     * Returns the mathematical absolute value of an {@code long} value
+     * if it is exactly representable as an {@code long}, throwing
+     * {@code ArithmeticException} if the result overflows the
+     * positive {@code long} range.
+     *
+     * <p>Since the range of two's complement integers is asymmetric
+     * with one additional negative value (JLS {@jls 4.2.1}), the
+     * mathematical absolute value of {@link Long#MIN_VALUE} overflows
+     * the positive {@code long} range, so an exception is thrown for
+     * that argument.
+     *
+     * @param  a  the argument whose absolute value is to be determined
+     * @return the absolute value of the argument, unless overflow occurs
+     * @throws ArithmeticException if the argument is {@link Long#MIN_VALUE}
+     * @see Math#abs(long)
+     * @since 15
+     */
+    public static long absExact(long a) {
+        if (a == Long.MIN_VALUE)
+            throw new ArithmeticException(
+                "Overflow to represent absolute value of Long.MIN_VALUE");
+        else
+            return abs(a);
+    }
+
+    /**
      * Returns the absolute value of a {@code float} value.
      * If the argument is not negative, the argument is returned.
      * If the argument is negative, the negation of the argument is returned.
--- a/src/java.base/share/classes/java/lang/StrictMath.java	Fri Mar 27 15:28:07 2020 +0100
+++ b/src/java.base/share/classes/java/lang/StrictMath.java	Mon Mar 30 13:49:02 2020 -0700
@@ -1124,36 +1124,86 @@
      * If the argument is not negative, the argument is returned.
      * If the argument is negative, the negation of the argument is returned.
      *
-     * <p>Note that if the argument is equal to the value of
-     * {@link Integer#MIN_VALUE}, the most negative representable
-     * {@code int} value, the result is that same value, which is
-     * negative.
+     * <p>Note that if the argument is equal to the value of {@link
+     * Integer#MIN_VALUE}, the most negative representable {@code int}
+     * value, the result is that same value, which is negative. In
+     * contrast, the {@link StrictMath#absExact(int)} method throws an
+     * {@code ArithmeticException} for this value.
      *
      * @param   a   the  argument whose absolute value is to be determined.
      * @return  the absolute value of the argument.
+     * @see Math#absExact(int)
      */
     public static int abs(int a) {
         return Math.abs(a);
     }
 
     /**
+     * Returns the mathematical absolute value of an {@code int} value
+     * if it is exactly representable as an {@code int}, throwing
+     * {@code ArithmeticException} if the result overflows the
+     * positive {@code int} range.
+     *
+     * <p>Since the range of two's complement integers is asymmetric
+     * with one additional negative value (JLS {@jls 4.2.1}), the
+     * mathematical absolute value of {@link Integer#MIN_VALUE}
+     * overflows the positive {@code int} range, so an exception is
+     * thrown for that argument.
+     *
+     * @param  a  the argument whose absolute value is to be determined
+     * @return the absolute value of the argument, unless overflow occurs
+     * @throws ArithmeticException if the argument is {@link Integer#MIN_VALUE}
+     * @see Math#abs(int)
+     * @see Math#absExact(int)
+     * @since 15
+     */
+    public static int absExact(int a) {
+        return Math.absExact(a);
+    }
+
+    /**
      * Returns the absolute value of a {@code long} value.
      * If the argument is not negative, the argument is returned.
      * If the argument is negative, the negation of the argument is returned.
      *
-     * <p>Note that if the argument is equal to the value of
-     * {@link Long#MIN_VALUE}, the most negative representable
-     * {@code long} value, the result is that same value, which
-     * is negative.
+     * <p>Note that if the argument is equal to the value of {@link
+     * Long#MIN_VALUE}, the most negative representable {@code long}
+     * value, the result is that same value, which is negative. In
+     * contrast, the {@link StrictMath#absExact(long)} method throws
+     * an {@code ArithmeticException} for this value.
      *
      * @param   a   the  argument whose absolute value is to be determined.
      * @return  the absolute value of the argument.
+     * @see Math#absExact(long)
      */
     public static long abs(long a) {
         return Math.abs(a);
     }
 
     /**
+     * Returns the mathematical absolute value of an {@code long} value
+     * if it is exactly representable as an {@code long}, throwing
+     * {@code ArithmeticException} if the result overflows the
+     * positive {@code long} range.
+     *
+     * <p>Since the range of two's complement integers is asymmetric
+     * with one additional negative value (JLS {@jls 4.2.1}), the
+     * mathematical absolute value of {@link Long#MIN_VALUE} overflows
+     * the positive {@code long} range, so an exception is thrown for
+     * that argument.
+     *
+     * @param  a  the argument whose absolute value is to be determined
+     * @return the absolute value of the argument, unless overflow occurs
+     * @throws ArithmeticException if the argument is {@link Long#MIN_VALUE}
+     * @see Math#abs(long)
+     * @see Math#absExact(long)
+     * @since 15
+     */
+    public static long absExact(long a) {
+        return Math.absExact(a);
+    }
+
+    /**
      * Returns the absolute value of a {@code float} value.
      * If the argument is not negative, the argument is returned.
      * If the argument is negative, the negation of the argument is returned.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/Math/AbsTests.java	Mon Mar 30 13:49:02 2020 -0700
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2020, 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.util.function.*;
+
+/*
+ * @test
+ * @bug 8241374
+ * @summary Test abs and absExact for Math and StrictMath
+ */
+public class AbsTests {
+    private static int errors = 0;
+
+    public static void main(String... args) {
+        errors += testInRangeIntAbs();
+        errors += testIntMinValue();
+        errors += testInRangeLongAbs();
+        errors += testLongMinValue();
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors found testing abs.");
+        }
+    }
+
+    private static int testInRangeIntAbs() {
+        int errors = 0;
+        int[][] testCases  = {
+            // Argument to abs, expected result
+            {+0, 0},
+            {+1, 1},
+            {-1, 1},
+            {-2, 2},
+            {+2, 2},
+            {-Integer.MAX_VALUE, Integer.MAX_VALUE},
+            {+Integer.MAX_VALUE, Integer.MAX_VALUE}
+        };
+
+        for(var testCase : testCases) {
+            errors += testIntAbs(Math::abs,      testCase[0], testCase[1]);
+            errors += testIntAbs(Math::absExact, testCase[0], testCase[1]);
+        }
+        return errors;
+    }
+
+    private static int testIntMinValue() {
+        int errors = 0;
+        // Strange but true
+        errors += testIntAbs(Math::abs, Integer.MIN_VALUE, Integer.MIN_VALUE);
+
+        // Test exceptional behavior for absExact
+        try {
+            int result = Math.absExact(Integer.MIN_VALUE);
+            System.err.printf("Bad return value %d from Math.absExact(MIN_VALUE)%n",
+                              result);
+            errors++;
+        } catch (ArithmeticException ae) {
+            ; // Expected
+        }
+        return errors;
+    }
+
+    private static int testIntAbs(IntUnaryOperator absFunc,
+                           int argument, int expected) {
+        int result = absFunc.applyAsInt(argument);
+        if (result != expected) {
+            System.err.printf("Unexpected int abs result %d for argument %d%n",
+                                result, argument);
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    private static long testInRangeLongAbs() {
+        int errors = 0;
+        long[][] testCases  = {
+            // Argument to abs, expected result
+            {+0L, 0L},
+            {+1L, 1L},
+            {-1L, 1L},
+            {-2L, 2L},
+            {+2L, 2L},
+            {-Integer.MAX_VALUE, Integer.MAX_VALUE},
+            {+Integer.MAX_VALUE, Integer.MAX_VALUE},
+            { Integer.MIN_VALUE, -((long)Integer.MIN_VALUE)},
+            {-Long.MAX_VALUE, Long.MAX_VALUE},
+        };
+
+        for(var testCase : testCases) {
+            errors += testLongAbs(Math::abs,      testCase[0], testCase[1]);
+            errors += testLongAbs(Math::absExact, testCase[0], testCase[1]);
+        }
+        return errors;
+    }
+
+    private static int testLongMinValue() {
+        int errors = 0;
+        // Strange but true
+        errors += testLongAbs(Math::abs, Long.MIN_VALUE, Long.MIN_VALUE);
+
+        // Test exceptional behavior for absExact
+        try {
+            long result = Math.absExact(Long.MIN_VALUE);
+            System.err.printf("Bad return value %d from Math.absExact(MIN_VALUE)%n",
+                              result);
+            errors++;
+        } catch (ArithmeticException ae) {
+            ; // Expected
+        }
+        return errors;
+    }
+
+    private static int testLongAbs(LongUnaryOperator absFunc,
+                           long argument, long expected) {
+        long result = absFunc.applyAsLong(argument);
+        if (result != expected) {
+            System.err.printf("Unexpected long abs result %d for argument %d%n",
+                                result, argument);
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+}