8241374: add Math.absExact

Reviewed-by: smarks, chegar, bpb
This commit is contained in:
Joe Darcy 2020-03-30 13:49:02 -07:00
parent b7439a8ae3
commit 916f00acc1
3 changed files with 269 additions and 17 deletions
src/java.base/share/classes/java/lang
test/jdk/java/lang/Math

@ -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,37 +1355,93 @@ public final class Math {
* 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) {
return (a < 0) ? -a : 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)
* @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) {
return (a < 0) ? -a : 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)
* @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.

@ -1124,35 +1124,85 @@ public final class StrictMath {
* 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.

@ -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;
}
}
}