1 /* 2 * Copyright (c) 2003, 2016, 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 package org.graalvm.compiler.jtt.lang; 24 25 import java.util.ArrayList; 26 import java.util.Collection; 27 import java.util.List; 28 import java.util.Random; 29 30 import org.junit.Before; 31 import org.junit.Test; 32 import org.junit.runner.RunWith; 33 import org.junit.runners.Parameterized; 34 import org.junit.runners.Parameterized.Parameter; 35 import org.junit.runners.Parameterized.Parameters; 36 37 import org.graalvm.compiler.jtt.JTTTest; 38 39 import jdk.vm.ci.meta.ResolvedJavaMethod; 40 41 /** 42 * This has been converted to JUnit from the jtreg test test/java/lang/Math/Log10Tests.java in JDK8. 43 */ 44 @RunWith(Parameterized.class) 45 public final class Math_log10 extends JTTTest { 46 47 static final double LN_10 = StrictMath.log(10.0); 48 49 @Parameter(value = 0) public double input; 50 @Parameter(value = 1) public Number input2; 51 @Parameter(value = 2) public Number result; 52 @Parameter(value = 3) public Condition condition; 53 public Double computedResult; 54 55 enum Condition { 56 EQUALS, 57 THREE_ULPS, 58 MONOTONICITY 59 } 60 61 public static double log10(double v) { 62 return Math.log10(v); 63 } 64 65 public static boolean log10Monotonicity(double v, double v2) { 66 return Math.log10(v) < Math.log(v2); 67 } 68 69 @Test 70 public void testLog10() { 71 if (condition == Condition.MONOTONICITY) { 72 runTest("log10Monotonicity", input, input2.doubleValue()); 73 } else { 74 runTest("log10", input); 75 } 76 } 77 78 public static double strictLog10(double v) { 79 return StrictMath.log10(v); 80 } 81 82 public static boolean strictLog10Monotonicity(double v, double v2) { 83 return StrictMath.log10(v) < StrictMath.log(v2); 84 } 85 86 @Test 87 public void testStrictLog10() { 88 if (condition == Condition.MONOTONICITY) { 89 runTest("strictLog10Monotonicity", input, input2.doubleValue()); 90 } else { 91 runTest("strictLog10", input); 92 } 93 } 94 95 @Before 96 public void before() { 97 computedResult = null; 98 } 99 100 private static boolean checkFor3ulps(double expected, double result) { 101 return Math.abs(result - expected) / Math.ulp(expected) <= 3; 102 } 103 104 @Override 105 protected void assertDeepEquals(Object expected, Object actual) { 106 if (this.condition == Condition.THREE_ULPS) { 107 double actualValue = ((Number) actual).doubleValue(); 108 assertTrue("differs by more than 3 ulps: " + result.doubleValue() + "," + actualValue, checkFor3ulps(result.doubleValue(), actualValue)); 109 if (computedResult != null && actualValue != computedResult) { 110 /* 111 * This test detects difference in the actual result between the built in 112 * implementation and what Graal does. If it reaches this test then the value was 113 * within 3 ulps but differs in the exact amount. 114 * 115 * System.err.println("value for " + input + " is within 3 ulps but differs from 116 * computed value: " + computedResult + " " + actualValue); 117 */ 118 } 119 } else { 120 super.assertDeepEquals(expected, actual); 121 } 122 } 123 124 @Override 125 protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) { 126 Result actual = super.executeExpected(method, receiver, args); 127 if (actual.returnValue instanceof Number) { 128 computedResult = ((Number) actual.returnValue).doubleValue(); 129 assertDeepEquals(computedResult, actual.returnValue); 130 } 131 return actual; 132 } 133 134 static void addEqualityTest(List<Object[]> tests, double input, double expected) { 135 tests.add(new Object[]{input, null, expected, Condition.EQUALS}); 136 } 137 138 static void add3UlpTest(List<Object[]> tests, double input, double expected) { 139 tests.add(new Object[]{input, null, expected, Condition.THREE_ULPS}); 140 } 141 142 static void addMonotonicityTest(List<Object[]> tests, double input, double input2) { 143 tests.add(new Object[]{input, input2, null, Condition.MONOTONICITY}); 144 } 145 146 @Parameters(name = "{index}") 147 public static Collection<Object[]> data() { 148 List<Object[]> tests = new ArrayList<>(); 149 150 addEqualityTest(tests, Double.NaN, Double.NaN); 151 addEqualityTest(tests, Double.longBitsToDouble(0x7FF0000000000001L), Double.NaN); 152 addEqualityTest(tests, Double.longBitsToDouble(0xFFF0000000000001L), Double.NaN); 153 addEqualityTest(tests, Double.longBitsToDouble(0x7FF8555555555555L), Double.NaN); 154 addEqualityTest(tests, Double.longBitsToDouble(0xFFF8555555555555L), Double.NaN); 155 addEqualityTest(tests, Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), Double.NaN); 156 addEqualityTest(tests, Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), Double.NaN); 157 addEqualityTest(tests, Double.longBitsToDouble(0x7FFDeadBeef00000L), Double.NaN); 158 addEqualityTest(tests, Double.longBitsToDouble(0xFFFDeadBeef00000L), Double.NaN); 159 addEqualityTest(tests, Double.longBitsToDouble(0x7FFCafeBabe00000L), Double.NaN); 160 addEqualityTest(tests, Double.longBitsToDouble(0xFFFCafeBabe00000L), Double.NaN); 161 addEqualityTest(tests, Double.NEGATIVE_INFINITY, Double.NaN); 162 addEqualityTest(tests, -8.0, Double.NaN); 163 addEqualityTest(tests, -1.0, Double.NaN); 164 addEqualityTest(tests, -Double.MIN_NORMAL, Double.NaN); 165 addEqualityTest(tests, -Double.MIN_VALUE, Double.NaN); 166 addEqualityTest(tests, -0.0, -Double.POSITIVE_INFINITY); 167 addEqualityTest(tests, +0.0, -Double.POSITIVE_INFINITY); 168 addEqualityTest(tests, +1.0, 0.0); 169 addEqualityTest(tests, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); 170 171 // Test log10(10^n) == n for integer n; 10^n, n < 0 is not 172 // exactly representable as a floating-point value -- up to 173 // 10^22 can be represented exactly 174 double testCase = 1.0; 175 for (int i = 0; i < 23; i++) { 176 addEqualityTest(tests, testCase, i); 177 testCase *= 10.0; 178 } 179 180 // Test for gross inaccuracy by comparing to log; should be 181 // within a few ulps of log(x)/log(10) 182 Random rand = new java.util.Random(0L); 183 for (int i = 0; i < 10000; i++) { 184 double input = Double.longBitsToDouble(rand.nextLong()); 185 if (!Double.isFinite(input)) { 186 continue; // avoid testing NaN and infinite values 187 } else { 188 input = Math.abs(input); 189 190 double expected = StrictMath.log(input) / LN_10; 191 if (!Double.isFinite(expected)) { 192 continue; // if log(input) overflowed, try again 193 } else { 194 add3UlpTest(tests, input, expected); 195 } 196 } 197 } 198 199 double z = Double.NaN; 200 // Test inputs greater than 1.0. 201 double[] input = new double[40]; 202 int half = input.length / 2; 203 // Initialize input to the 40 consecutive double values 204 // "centered" at 1.0. 205 double up = Double.NaN; 206 double down = Double.NaN; 207 for (int i = 0; i < half; i++) { 208 if (i == 0) { 209 input[half] = 1.0; 210 up = Math.nextUp(1.0); 211 down = Math.nextDown(1.0); 212 } else { 213 input[half + i] = up; 214 input[half - i] = down; 215 up = Math.nextUp(up); 216 down = Math.nextDown(down); 217 } 218 } 219 input[0] = Math.nextDown(input[1]); 220 for (int i = 0; i < input.length; i++) { 221 // Test accuracy. 222 z = input[i] - 1.0; 223 double expected = (z - (z * z) * 0.5) / LN_10; 224 add3UlpTest(tests, input[i], expected); 225 226 // Test monotonicity 227 if (i > 0) { 228 addMonotonicityTest(tests, input[i - 1], input[i]); 229 } 230 } 231 232 return tests; 233 } 234 235 }