1 /* 2 * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.jtt.lang; 26 27 import java.util.ArrayList; 28 import java.util.Collection; 29 import java.util.List; 30 import java.util.Random; 31 32 import org.junit.Before; 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 import org.junit.runners.Parameterized; 36 import org.junit.runners.Parameterized.Parameter; 37 import org.junit.runners.Parameterized.Parameters; 38 39 import org.graalvm.compiler.jtt.JTTTest; 40 41 import jdk.vm.ci.meta.ResolvedJavaMethod; 42 43 /** 44 * This has been converted to JUnit from the jtreg test test/java/lang/Math/Log10Tests.java in JDK8. 45 */ 46 @RunWith(Parameterized.class) 47 public final class Math_log10 extends JTTTest { 48 49 static final double LN_10 = StrictMath.log(10.0); 50 51 @Parameter(value = 0) public double input; 52 @Parameter(value = 1) public Number input2; 53 @Parameter(value = 2) public Number result; 54 @Parameter(value = 3) public Condition condition; 55 public Double computedResult; 56 57 enum Condition { 58 EQUALS, 59 THREE_ULPS, 60 MONOTONICITY 61 } 62 63 public static double log10(double v) { 64 return Math.log10(v); 65 } 66 67 public static boolean log10Monotonicity(double v, double v2) { 68 return Math.log10(v) < Math.log(v2); 69 } 70 71 @Test 72 public void testLog10() { 73 if (condition == Condition.MONOTONICITY) { 74 runTest("log10Monotonicity", input, input2.doubleValue()); 75 } else { 76 runTest("log10", input); 77 } 78 } 79 80 public static double strictLog10(double v) { 81 return StrictMath.log10(v); 82 } 83 84 public static boolean strictLog10Monotonicity(double v, double v2) { 85 return StrictMath.log10(v) < StrictMath.log(v2); 86 } 87 88 @Test 89 public void testStrictLog10() { 90 if (condition == Condition.MONOTONICITY) { 91 runTest("strictLog10Monotonicity", input, input2.doubleValue()); 92 } else { 93 runTest("strictLog10", input); 94 } 95 } 96 97 @Before 98 public void before() { 99 computedResult = null; 100 } 101 102 private static boolean checkFor3ulps(double expected, double result) { 103 return Math.abs(result - expected) / Math.ulp(expected) <= 3; 104 } 105 106 @Override 107 protected void assertDeepEquals(Object expected, Object actual) { 108 if (this.condition == Condition.THREE_ULPS) { 109 double actualValue = ((Number) actual).doubleValue(); 110 assertTrue("differs by more than 3 ulps: " + result.doubleValue() + "," + actualValue, checkFor3ulps(result.doubleValue(), actualValue)); 111 if (computedResult != null && actualValue != computedResult) { 112 /* 113 * This test detects difference in the actual result between the built in 114 * implementation and what Graal does. If it reaches this test then the value was 115 * within 3 ulps but differs in the exact amount. 116 * 117 * System.err.println("value for " + input + " is within 3 ulps but differs from 118 * computed value: " + computedResult + " " + actualValue); 119 */ 120 } 121 } else { 122 super.assertDeepEquals(expected, actual); 123 } 124 } 125 126 @Override 127 protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) { 128 Result actual = super.executeExpected(method, receiver, args); 129 if (actual.returnValue instanceof Number) { 130 computedResult = ((Number) actual.returnValue).doubleValue(); 131 assertDeepEquals(computedResult, actual.returnValue); 132 } 133 return actual; 134 } 135 136 static void addEqualityTest(List<Object[]> tests, double input, double expected) { 137 tests.add(new Object[]{input, null, expected, Condition.EQUALS}); 138 } 139 140 static void add3UlpTest(List<Object[]> tests, double input, double expected) { 141 tests.add(new Object[]{input, null, expected, Condition.THREE_ULPS}); 142 } 143 144 static void addMonotonicityTest(List<Object[]> tests, double input, double input2) { 145 tests.add(new Object[]{input, input2, null, Condition.MONOTONICITY}); 146 } 147 148 @Parameters(name = "{index}") 149 public static Collection<Object[]> data() { 150 List<Object[]> tests = new ArrayList<>(); 151 152 addEqualityTest(tests, Double.NaN, Double.NaN); 153 addEqualityTest(tests, Double.longBitsToDouble(0x7FF0000000000001L), Double.NaN); 154 addEqualityTest(tests, Double.longBitsToDouble(0xFFF0000000000001L), Double.NaN); 155 addEqualityTest(tests, Double.longBitsToDouble(0x7FF8555555555555L), Double.NaN); 156 addEqualityTest(tests, Double.longBitsToDouble(0xFFF8555555555555L), Double.NaN); 157 addEqualityTest(tests, Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), Double.NaN); 158 addEqualityTest(tests, Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), Double.NaN); 159 addEqualityTest(tests, Double.longBitsToDouble(0x7FFDeadBeef00000L), Double.NaN); 160 addEqualityTest(tests, Double.longBitsToDouble(0xFFFDeadBeef00000L), Double.NaN); 161 addEqualityTest(tests, Double.longBitsToDouble(0x7FFCafeBabe00000L), Double.NaN); 162 addEqualityTest(tests, Double.longBitsToDouble(0xFFFCafeBabe00000L), Double.NaN); 163 addEqualityTest(tests, Double.NEGATIVE_INFINITY, Double.NaN); 164 addEqualityTest(tests, -8.0, Double.NaN); 165 addEqualityTest(tests, -1.0, Double.NaN); 166 addEqualityTest(tests, -Double.MIN_NORMAL, Double.NaN); 167 addEqualityTest(tests, -Double.MIN_VALUE, Double.NaN); 168 addEqualityTest(tests, -0.0, -Double.POSITIVE_INFINITY); 169 addEqualityTest(tests, +0.0, -Double.POSITIVE_INFINITY); 170 addEqualityTest(tests, +1.0, 0.0); 171 addEqualityTest(tests, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); 172 173 // Test log10(10^n) == n for integer n; 10^n, n < 0 is not 174 // exactly representable as a floating-point value -- up to 175 // 10^22 can be represented exactly 176 double testCase = 1.0; 177 for (int i = 0; i < 23; i++) { 178 addEqualityTest(tests, testCase, i); 179 testCase *= 10.0; 180 } 181 182 // Test for gross inaccuracy by comparing to log; should be 183 // within a few ulps of log(x)/log(10) 184 Random rand = new java.util.Random(0L); 185 for (int i = 0; i < 500; i++) { 186 double input = Double.longBitsToDouble(rand.nextLong()); 187 if (!Double.isFinite(input)) { 188 continue; // avoid testing NaN and infinite values 189 } else { 190 input = Math.abs(input); 191 192 double expected = StrictMath.log(input) / LN_10; 193 if (!Double.isFinite(expected)) { 194 continue; // if log(input) overflowed, try again 195 } else { 196 add3UlpTest(tests, input, expected); 197 } 198 } 199 } 200 201 double z = Double.NaN; 202 // Test inputs greater than 1.0. 203 double[] input = new double[40]; 204 int half = input.length / 2; 205 // Initialize input to the 40 consecutive double values 206 // "centered" at 1.0. 207 double up = Double.NaN; 208 double down = Double.NaN; 209 for (int i = 0; i < half; i++) { 210 if (i == 0) { 211 input[half] = 1.0; 212 up = Math.nextUp(1.0); 213 down = Math.nextDown(1.0); 214 } else { 215 input[half + i] = up; 216 input[half - i] = down; 217 up = Math.nextUp(up); 218 down = Math.nextDown(down); 219 } 220 } 221 input[0] = Math.nextDown(input[1]); 222 for (int i = 0; i < input.length; i++) { 223 // Test accuracy. 224 z = input[i] - 1.0; 225 double expected = (z - (z * z) * 0.5) / LN_10; 226 add3UlpTest(tests, input[i], expected); 227 228 // Test monotonicity 229 if (i > 0) { 230 addMonotonicityTest(tests, input[i - 1], input[i]); 231 } 232 } 233 234 return tests; 235 } 236 237 }