8301226: Add clamp() methods to java.lang.Math and to StrictMath
Reviewed-by: qamai, darcy
This commit is contained in:
parent
13b1ebba27
commit
94e7cc8587
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2023, 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
|
||||
@ -2191,6 +2191,135 @@ public final class Math {
|
||||
return (a <= b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned.
|
||||
* <p>
|
||||
* While the original value of type long may not fit into the int type,
|
||||
* the bounds have the int type, so the result always fits the int type.
|
||||
* This allows to use method to safely cast long value to int with
|
||||
* saturation.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if {@code min > max}
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static int clamp(long value, int min, int max) {
|
||||
if (min > max) {
|
||||
throw new IllegalArgumentException(min + " > " + max);
|
||||
}
|
||||
return (int) Math.min(max, Math.max(value, min));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if {@code min > max}
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static long clamp(long value, long min, long max) {
|
||||
if (min > max) {
|
||||
throw new IllegalArgumentException(min + " > " + max);
|
||||
}
|
||||
return Math.min(max, Math.max(value, min));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned. If value is NaN, the result is also NaN.
|
||||
* <p>
|
||||
* Unlike the numerical comparison operators, this method considers
|
||||
* negative zero to be strictly smaller than positive zero.
|
||||
* E.g., {@code clamp(-0.0, 0.0, 1.0)} returns 0.0.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if either of {@code min} and {@code max}
|
||||
* arguments is NaN, or {@code min > max}, or {@code min} is +0.0, and
|
||||
* {@code max} is -0.0.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static double clamp(double value, double min, double max) {
|
||||
// This unusual condition allows keeping only one branch
|
||||
// on common path when min < max and neither of them is NaN.
|
||||
// If min == max, we should additionally check for +0.0/-0.0 case,
|
||||
// so we're still visiting the if statement.
|
||||
if (!(min < max)) { // min greater than, equal to, or unordered with respect to max; NaN values are unordered
|
||||
if (Double.isNaN(min)) {
|
||||
throw new IllegalArgumentException("min is NaN");
|
||||
}
|
||||
if (Double.isNaN(max)) {
|
||||
throw new IllegalArgumentException("max is NaN");
|
||||
}
|
||||
if (Double.compare(min, max) > 0) {
|
||||
throw new IllegalArgumentException(min + " > " + max);
|
||||
}
|
||||
// Fall-through if min and max are exactly equal (or min = -0.0 and max = +0.0)
|
||||
// and none of them is NaN
|
||||
}
|
||||
return Math.min(max, Math.max(value, min));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned. If value is NaN, the result is also NaN.
|
||||
* <p>
|
||||
* Unlike the numerical comparison operators, this method considers
|
||||
* negative zero to be strictly smaller than positive zero.
|
||||
* E.g., {@code clamp(-0.0f, 0.0f, 1.0f)} returns 0.0f.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if either of {@code min} and {@code max}
|
||||
* arguments is NaN, or {@code min > max}, or {@code min} is +0.0f, and
|
||||
* {@code max} is -0.0f.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static float clamp(float value, float min, float max) {
|
||||
// This unusual condition allows keeping only one branch
|
||||
// on common path when min < max and neither of them is NaN.
|
||||
// If min == max, we should additionally check for +0.0/-0.0 case,
|
||||
// so we're still visiting the if statement.
|
||||
if (!(min < max)) { // min greater than, equal to, or unordered with respect to max; NaN values are unordered
|
||||
if (Float.isNaN(min)) {
|
||||
throw new IllegalArgumentException("min is NaN");
|
||||
}
|
||||
if (Float.isNaN(max)) {
|
||||
throw new IllegalArgumentException("max is NaN");
|
||||
}
|
||||
if (Float.compare(min, max) > 0) {
|
||||
throw new IllegalArgumentException(min + " > " + max);
|
||||
}
|
||||
// Fall-through if min and max are exactly equal (or min = -0.0 and max = +0.0)
|
||||
// and none of them is NaN
|
||||
}
|
||||
return Math.min(max, Math.max(value, min));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fused multiply add of the three arguments; that is,
|
||||
* returns the exact product of the first two arguments summed
|
||||
|
@ -1759,6 +1759,95 @@ public final class StrictMath {
|
||||
return Math.min(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned.
|
||||
* <p>
|
||||
* While the original value of type long may not fit into the int type,
|
||||
* the bounds have the int type, so the result always fits the int type.
|
||||
* This allows to use method to safely cast long value to int with
|
||||
* saturation.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if {@code min > max}
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static int clamp(long value, int min, int max) {
|
||||
return Math.clamp(value, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if {@code min > max}
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static long clamp(long value, long min, long max) {
|
||||
return Math.clamp(value, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned. If value is NaN, the result is also NaN.
|
||||
* <p>
|
||||
* Unlike the numerical comparison operators, this method considers
|
||||
* negative zero to be strictly smaller than positive zero.
|
||||
* E.g., {@code clamp(-0.0, 0.0, 1.0)} returns 0.0.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if either of {@code min} and {@code max}
|
||||
* arguments is NaN, or {@code min > max}, or {@code min} is +0.0, and
|
||||
* {@code max} is -0.0.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static double clamp(double value, double min, double max) {
|
||||
return Math.clamp(value, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to fit between min and max. If the value is less
|
||||
* than {@code min}, then {@code min} is returned. If the value is greater
|
||||
* than {@code max}, then {@code max} is returned. Otherwise, the original
|
||||
* value is returned. If value is NaN, the result is also NaN.
|
||||
* <p>
|
||||
* Unlike the numerical comparison operators, this method considers
|
||||
* negative zero to be strictly smaller than positive zero.
|
||||
* E.g., {@code clamp(-0.0f, 0.0f, 1.0f)} returns 0.0f.
|
||||
*
|
||||
* @param value value to clamp
|
||||
* @param min minimal allowed value
|
||||
* @param max maximal allowed value
|
||||
* @return a clamped value that fits into {@code min..max} interval
|
||||
* @throws IllegalArgumentException if either of {@code min} and {@code max}
|
||||
* arguments is NaN, or {@code min > max}, or {@code min} is +0.0f, and
|
||||
* {@code max} is -0.0f.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
public static float clamp(float value, float min, float max) {
|
||||
return Math.clamp(value, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fused multiply add of the three arguments; that is,
|
||||
* returns the exact product of the first two arguments summed
|
||||
|
281
test/jdk/java/lang/Math/Clamp.java
Normal file
281
test/jdk/java/lang/Math/Clamp.java
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
@bug 8301226
|
||||
@summary Add clamp() methods to java.lang.Math
|
||||
*/
|
||||
|
||||
|
||||
public class Clamp {
|
||||
public static void main(String[] args) {
|
||||
int failures = 0;
|
||||
|
||||
failures += testIntClamp();
|
||||
failures += testLongClamp();
|
||||
failures += testDoubleClamp();
|
||||
failures += testFloatClamp();
|
||||
|
||||
if (failures > 0) {
|
||||
System.err.println("Testing clamp incurred " + failures + " failures.");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static int testIntClamp() {
|
||||
int failures = 0;
|
||||
long[][] tests = {
|
||||
// value, min, max, expected
|
||||
{0, 1, 2, 1},
|
||||
{0, 0, 2, 0},
|
||||
{1, 0, 2, 1},
|
||||
{2, 0, 2, 2},
|
||||
{3, 0, 2, 2},
|
||||
{0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0},
|
||||
{Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE},
|
||||
{Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE},
|
||||
{Long.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE},
|
||||
{Long.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE},
|
||||
{0, 1, 1, 1},
|
||||
{Long.MAX_VALUE, 1, 1, 1}
|
||||
};
|
||||
long[][] exceptionTests = {
|
||||
// value, min, max
|
||||
{1, 2, 0},
|
||||
{1, Integer.MAX_VALUE, Integer.MIN_VALUE}
|
||||
};
|
||||
for (long[] test : tests) {
|
||||
long value = test[0];
|
||||
int min = Math.toIntExact(test[1]);
|
||||
int max = Math.toIntExact(test[2]);
|
||||
int expected = Math.toIntExact(test[3]);
|
||||
failures += checkEquals("(int) Math.clamp(" + value + ", " + min + ", " + max + ")", Math.clamp(value, min, max), expected);
|
||||
failures += checkEquals("(int) StrictMath.clamp(" + value + ", " + min + ", " + max + ")", StrictMath.clamp(value, min, max), expected);
|
||||
}
|
||||
for (long[] test : exceptionTests) {
|
||||
long value = test[0];
|
||||
int min = Math.toIntExact(test[1]);
|
||||
int max = Math.toIntExact(test[2]);
|
||||
failures += checkIllegalArgumentException("(int) Math.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> Math.clamp(value, min, max));
|
||||
failures += checkIllegalArgumentException("(int) StrictMath.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> StrictMath.clamp(value, min, max));
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
private static int testLongClamp() {
|
||||
int failures = 0;
|
||||
long[][] tests = {
|
||||
// value, min, max, expected
|
||||
{0L, 1L, 2L, 1L},
|
||||
{0L, 0L, 2L, 0L},
|
||||
{1L, 0L, 2L, 1L},
|
||||
{2L, 0L, 2L, 2L},
|
||||
{3L, 0L, 2L, 2L},
|
||||
{0L, Long.MIN_VALUE, Long.MAX_VALUE, 0},
|
||||
{Long.MIN_VALUE, Long.MIN_VALUE, Long.MAX_VALUE, Long.MIN_VALUE},
|
||||
{Long.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE, Long.MAX_VALUE},
|
||||
{0, 1, 1, 1},
|
||||
{Long.MAX_VALUE, 1, 1, 1}
|
||||
};
|
||||
long[][] exceptionTests = {
|
||||
// value, min, max
|
||||
{1L, 2L, 0L},
|
||||
{1, Long.MAX_VALUE, Long.MIN_VALUE}
|
||||
};
|
||||
for (long[] test : tests) {
|
||||
long value = test[0];
|
||||
long min = test[1];
|
||||
long max = test[2];
|
||||
long expected = test[3];
|
||||
failures += checkEquals("(long) Math.clamp(" + value + ", " + min + ", " + max + ")", Math.clamp(value, min, max), expected);
|
||||
failures += checkEquals("(long) StrictMath.clamp(" + value + ", " + min + ", " + max + ")", StrictMath.clamp(value, min, max), expected);
|
||||
}
|
||||
for (long[] test : exceptionTests) {
|
||||
long value = test[0];
|
||||
long min = test[1];
|
||||
long max = test[2];
|
||||
failures += checkIllegalArgumentException("(long) Math.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> Math.clamp(value, min, max));
|
||||
failures += checkIllegalArgumentException("(long) StrictMath.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> StrictMath.clamp(value, min, max));
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
private static int testDoubleClamp() {
|
||||
int failures = 0;
|
||||
double[][] tests = {
|
||||
// value, min, max, expected
|
||||
{-0.1, 0.0, 0.5, 0.0},
|
||||
{-0.0, 0.0, 0.5, 0.0},
|
||||
{0.0, 0.0, 0.5, 0.0},
|
||||
{Double.MIN_VALUE, 0.0, 0.5, Double.MIN_VALUE},
|
||||
{0.2, 0.0, 0.5, 0.2},
|
||||
{Math.nextDown(0.5), 0.0, 0.5, Math.nextDown(0.5)},
|
||||
{0.5, 0.0, 0.5, 0.5},
|
||||
{Math.nextUp(0.5), 0.0, 0.5, 0.5},
|
||||
{0.6, 0.0, 0.5, 0.5},
|
||||
|
||||
{Double.MAX_VALUE, 0.0, Double.POSITIVE_INFINITY, Double.MAX_VALUE},
|
||||
{Double.POSITIVE_INFINITY, 0.0, Double.MAX_VALUE, Double.MAX_VALUE},
|
||||
{-Double.MAX_VALUE, Double.NEGATIVE_INFINITY, 0.0, -Double.MAX_VALUE},
|
||||
{Double.NEGATIVE_INFINITY, -Double.MAX_VALUE, 0.0, -Double.MAX_VALUE},
|
||||
|
||||
{-1.0, -0.0, 0.0, -0.0},
|
||||
{-0.0, -0.0, 0.0, -0.0},
|
||||
{0.0, -0.0, 0.0, 0.0},
|
||||
{1.0, -0.0, 0.0, 0.0},
|
||||
{-1.0, 0.0, 0.0, 0.0},
|
||||
{-0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0},
|
||||
{1.0, 0.0, 0.0, 0.0},
|
||||
{-1.0, -0.0, -0.0, -0.0},
|
||||
{-0.0, -0.0, -0.0, -0.0},
|
||||
{0.0, -0.0, -0.0, -0.0},
|
||||
{1.0, -0.0, -0.0, -0.0},
|
||||
|
||||
{Double.NaN, 0.0, 1.0, Double.NaN},
|
||||
{Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN}
|
||||
};
|
||||
double[][] exceptionTests = {
|
||||
// value, min, max
|
||||
{0.0, Double.NaN, Double.NaN},
|
||||
{0.0, 0.0, Double.NaN},
|
||||
{0.0, Double.NaN, 0.0},
|
||||
{Double.NaN, 1.0, 0.0},
|
||||
{0.0, 0.0, -0.0},
|
||||
{0.0, 1.0, -1.0}
|
||||
};
|
||||
for (double[] test : tests) {
|
||||
double value = test[0];
|
||||
double min = test[1];
|
||||
double max = test[2];
|
||||
double expected = test[3];
|
||||
failures += checkEquals("(double) Math.clamp(" + value + ", " + min + ", " + max + ")", Math.clamp(value, min, max), expected);
|
||||
failures += checkEquals("(double) StrictMath.clamp(" + value + ", " + min + ", " + max + ")", StrictMath.clamp(value, min, max), expected);
|
||||
}
|
||||
for (double[] test : exceptionTests) {
|
||||
double value = test[0];
|
||||
double min = test[1];
|
||||
double max = test[2];
|
||||
failures += checkIllegalArgumentException("(double) Math.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> Math.clamp(value, min, max));
|
||||
failures += checkIllegalArgumentException("(double) StrictMath.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> StrictMath.clamp(value, min, max));
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
private static int testFloatClamp() {
|
||||
int failures = 0;
|
||||
float[][] tests = {
|
||||
// value, min, max, expected
|
||||
{-0.1f, 0.0f, 0.5f, 0.0f},
|
||||
{-0.0f, 0.0f, 0.5f, 0.0f},
|
||||
{0.0f, 0.0f, 0.5f, 0.0f},
|
||||
{Float.MIN_VALUE, 0.0f, 0.5f, Float.MIN_VALUE},
|
||||
{0.2f, 0.0f, 0.5f, 0.2f},
|
||||
{Math.nextDown(0.5f), 0.0f, 0.5f, Math.nextDown(0.5f)},
|
||||
{0.5f, 0.0f, 0.5f, 0.5f},
|
||||
{Math.nextUp(0.5f), 0.0f, 0.5f, 0.5f},
|
||||
{0.6f, 0.0f, 0.5f, 0.5f},
|
||||
|
||||
{Float.MAX_VALUE, 0.0f, Float.POSITIVE_INFINITY, Float.MAX_VALUE},
|
||||
{Float.POSITIVE_INFINITY, 0.0f, Float.MAX_VALUE, Float.MAX_VALUE},
|
||||
{-Float.MAX_VALUE, Float.NEGATIVE_INFINITY, 0.0f, -Float.MAX_VALUE},
|
||||
{Float.NEGATIVE_INFINITY, -Float.MAX_VALUE, 0.0f, -Float.MAX_VALUE},
|
||||
|
||||
{-1.0f, -0.0f, 0.0f, -0.0f},
|
||||
{-0.0f, -0.0f, 0.0f, -0.0f},
|
||||
{0.0f, -0.0f, 0.0f, 0.0f},
|
||||
{1.0f, -0.0f, 0.0f, 0.0f},
|
||||
{-1.0f, 0.0f, 0.0f, 0.0f},
|
||||
{-0.0f, 0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 0.0f, 0.0f, 0.0f},
|
||||
{1.0f, 0.0f, 0.0f, 0.0f},
|
||||
{-1.0f, -0.0f, -0.0f, -0.0f},
|
||||
{-0.0f, -0.0f, -0.0f, -0.0f},
|
||||
{0.0f, -0.0f, -0.0f, -0.0f},
|
||||
{1.0f, -0.0f, -0.0f, -0.0f},
|
||||
|
||||
{Float.NaN, 0.0f, 1.0f, Float.NaN},
|
||||
{Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN}
|
||||
};
|
||||
float[][] exceptionTests = {
|
||||
// value, min, max
|
||||
{0.0f, Float.NaN, Float.NaN},
|
||||
{0.0f, 0.0f, Float.NaN},
|
||||
{0.0f, Float.NaN, 0.0f},
|
||||
{Float.NaN, 1.0f, 0.0f},
|
||||
{0.0f, 0.0f, -0.0f},
|
||||
{0.0f, 1.0f, -1.0f}
|
||||
};
|
||||
for (float[] test : tests) {
|
||||
float value = test[0];
|
||||
float min = test[1];
|
||||
float max = test[2];
|
||||
float expected = test[3];
|
||||
failures += checkEquals("(float) Math.clamp(" + value + ", " + min + ", " + max + ")", Math.clamp(value, min, max), expected);
|
||||
failures += checkEquals("(float) StrictMath.clamp(" + value + ", " + min + ", " + max + ")", StrictMath.clamp(value, min, max), expected);
|
||||
}
|
||||
for (float[] test : exceptionTests) {
|
||||
float value = test[0];
|
||||
float min = test[1];
|
||||
float max = test[2];
|
||||
failures += checkIllegalArgumentException("(float) Math.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> Math.clamp(value, min, max));
|
||||
failures += checkIllegalArgumentException("(float) StrictMath.clamp(" + value + ", " + min + ", " + max + ")",
|
||||
() -> StrictMath.clamp(value, min, max));
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
private static int checkIllegalArgumentException(String what, Runnable r) {
|
||||
try {
|
||||
r.run();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
return 0;
|
||||
}
|
||||
System.err.println(what+": missing expected exception");
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int checkEquals(String what, double actual, double expected) {
|
||||
if (Double.doubleToLongBits(actual) != Double.doubleToLongBits(expected)) {
|
||||
System.err.println(what + ": expected = " + expected + "; actual = " + actual);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int checkEquals(String what, long actual, long expected) {
|
||||
if (actual != expected) {
|
||||
System.err.println(what + ": expected = " + expected + "; actual = " + actual);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user