/* * 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; } }