diff --git a/test/jdk/java/lang/StrictMath/ExhaustingTests.java b/test/jdk/java/lang/StrictMath/ExhaustingTests.java new file mode 100644 index 00000000000..09e182d4e16 --- /dev/null +++ b/test/jdk/java/lang/StrictMath/ExhaustingTests.java @@ -0,0 +1,169 @@ +/* + * 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 8301833 + * @build Tests + * @build FdlibmTranslit + * @build ExhaustingTests + * @run main ExhaustingTests + * @summary Compare StrictMath.foo and FdlibmTranslit.foo for many inputs. + */ + +/* + * Note on usage: for more exhaustive testing to help validate changes + * to StrictMath, the DEFAULT_SHIFT setting should be set to 0. This + * will test all float values against the unary methods. Running all + * the float values for a single method takes on the order of a minute + * or two. The default setting is a shift of 10, meaning every 1024th + * float value is tested and the overall test runs within the typical + * time expectations of a tier 1 test. + */ + +import java.util.function.DoubleBinaryOperator; +import java.util.function.DoubleUnaryOperator; + +public class ExhaustingTests { + public static void main(String... args) { + long failures = 0; + + failures += testUnaryMethods(); + failures += testBinaryMethods(); + + if (failures > 0) { + System.err.println("Comparing StrictMath and FdlibmTranslit" + + " incurred " + failures + " failures."); + throw new RuntimeException(); + } + } + + private static final int DEFAULT_SHIFT = 10; + + /** + * Test the unary (one-argument) StrictMath methods from FDLIBM. + */ + private static long testUnaryMethods() { + long failures = 0; + UnaryTestCase[] testCases = { + // new UnaryTestCase("sqrt", FdlibmTranslit::sqrt, StrictMath::sqrt, DEFAULT_SHIFT), + new UnaryTestCase("cbrt", FdlibmTranslit::cbrt, StrictMath::cbrt, DEFAULT_SHIFT), + + new UnaryTestCase("log", FdlibmTranslit::log, StrictMath::log, DEFAULT_SHIFT), + new UnaryTestCase("log10", FdlibmTranslit::log10, StrictMath::log10, DEFAULT_SHIFT), + new UnaryTestCase("log1p", FdlibmTranslit::log1p, StrictMath::log1p, DEFAULT_SHIFT), + + // new UnaryTestCase("exp", FdlibmTranslit::exp, StrictMath::exp, DEFAULT_SHIFT), + new UnaryTestCase("expm1", FdlibmTranslit::expm1, StrictMath::expm1, DEFAULT_SHIFT), + + // new UnaryTestCase("sinh", FdlibmTranslit::sinh, StrictMath::sinh, DEFAULT_SHIFT), + // new UnaryTestCase("cosh", FdlibmTranslit::cosh, StrictMath::cosh, DEFAULT_SHIFT), + // new UnaryTestCase("tanh", FdlibmTranslit::tanh, StrictMath::tanh, DEFAULT_SHIFT), + + // new UnaryTestCase("sin", FdlibmTranslit::sin, StrictMath::sin, DEFAULT_SHIFT), + // new UnaryTestCase("cos", FdlibmTranslit::cos, StrictMath::cos, DEFAULT_SHIFT), + // new UnaryTestCase("tan", FdlibmTranslit::tan, StrictMath::tan, DEFAULT_SHIFT), + + // new UnaryTestCase("asin", FdlibmTranslit::asin, StrictMath::asin, DEFAULT_SHIFT), + // new UnaryTestCase("acos", FdlibmTranslit::acos, StrictMath::acos, DEFAULT_SHIFT), + // new UnaryTestCase("atan", FdlibmTranslit::atan, StrictMath::atan, DEFAULT_SHIFT), + }; + + for (var testCase : testCases) { + System.out.println("Testing " + testCase.name()); + System.out.flush(); + int i = Integer.MAX_VALUE; // overflow to Integer.MIN_VALUE at start of loop + int increment = 1 << testCase.shiftDistance; + do { + i += increment; + double input = (double)Float.intBitsToFloat(i); + failures += Tests.test(testCase.name(), + input, + testCase.strictMath, + testCase.translit.applyAsDouble(input)); + } while (i != Integer.MAX_VALUE); + } + return failures; + } + + private static record UnaryTestCase(String name, + DoubleUnaryOperator translit, + DoubleUnaryOperator strictMath, + int shiftDistance) { + UnaryTestCase { + if (shiftDistance < 0 || shiftDistance >= 31) { + throw new IllegalArgumentException("Shift out of range"); + } + } + } + + /** + * Test the binary (two-argument) StrictMath methods from FDLIBM. + */ + private static long testBinaryMethods() { + long failures = 0; + // Note: pow does _not_ have translit a port + + // Shift of 16 for a binary method gives comparable running + // time to exhaustive testing of a unary method (testing every + // 2^16 floating point values over two arguments is 2^32 + // probes). + BinaryTestCase[] testCases = { + new BinaryTestCase("hypot", FdlibmTranslit::hypot, StrictMath::hypot, 20, 20), + // new BinaryTestCase("atan2", FdlibmTranslit::atan2, StrictMath::atan2, 20, 20), + }; + + for (var testCase : testCases) { + System.out.println("Testing " + testCase.name()); + System.out.flush(); + + int iIncrement = 1 << testCase.xShift; + int jIncrement = 1 << testCase.yShift; + + for (long i = Integer.MIN_VALUE; i <= Integer.MAX_VALUE; i += iIncrement) { + for (long j = Integer.MIN_VALUE; j <= Integer.MAX_VALUE; j += jIncrement) { + double input1 = (double)Float.intBitsToFloat((int)i); + double input2 = (double)Float.intBitsToFloat((int)j); + failures += Tests.test(testCase.name(), + input1, input2, + testCase.strictMath, + testCase.translit.applyAsDouble(input1, input2)); + } + } + } + return failures; + } + + private static record BinaryTestCase(String name, + DoubleBinaryOperator translit, + DoubleBinaryOperator strictMath, + int xShift, + int yShift) { + BinaryTestCase { + if (xShift < 0 || xShift >= 31 || + yShift < 0 || yShift >= 31 ) { + throw new IllegalArgumentException("Shift out of range"); + } + } + } +}