HypotTests.java revision 17329:e0129da12f92
1/* 2 * Copyright (c) 2003, 2017, 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 * @test 26 * @library /test/lib 27 * @build jdk.test.lib.RandomFactory 28 * @run main HypotTests 29 * @bug 4851638 4939441 8078672 30 * @summary Tests for {Math, StrictMath}.hypot (use -Dseed=X to set PRNG seed) 31 * @author Joseph D. Darcy 32 * @key randomness 33 */ 34 35import jdk.test.lib.RandomFactory; 36 37public class HypotTests { 38 private HypotTests(){} 39 40 static final double infinityD = Double.POSITIVE_INFINITY; 41 static final double NaNd = Double.NaN; 42 43 /** 44 * Given integers m and n, assuming m < n, the triple (n^2 - m^2, 45 * 2mn, and n^2 + m^2) is a Pythagorean triple with a^2 + b^2 = 46 * c^2. This methods returns a long array holding the Pythagorean 47 * triple corresponding to the inputs. 48 */ 49 static long [] pythagoreanTriple(int m, int n) { 50 long M = m; 51 long N = n; 52 long result[] = new long[3]; 53 54 55 result[0] = Math.abs(M*M - N*N); 56 result[1] = Math.abs(2*M*N); 57 result[2] = Math.abs(M*M + N*N); 58 59 return result; 60 } 61 62 static int testHypot() { 63 int failures = 0; 64 65 double [][] testCases = { 66 // Special cases 67 {infinityD, infinityD, infinityD}, 68 {infinityD, 0.0, infinityD}, 69 {infinityD, 1.0, infinityD}, 70 {infinityD, NaNd, infinityD}, 71 {NaNd, NaNd, NaNd}, 72 {0.0, NaNd, NaNd}, 73 {1.0, NaNd, NaNd}, 74 {Double.longBitsToDouble(0x7FF0000000000001L), 1.0, NaNd}, 75 {Double.longBitsToDouble(0xFFF0000000000001L), 1.0, NaNd}, 76 {Double.longBitsToDouble(0x7FF8555555555555L), 1.0, NaNd}, 77 {Double.longBitsToDouble(0xFFF8555555555555L), 1.0, NaNd}, 78 {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), 1.0, NaNd}, 79 {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), 1.0, NaNd}, 80 {Double.longBitsToDouble(0x7FFDeadBeef00000L), 1.0, NaNd}, 81 {Double.longBitsToDouble(0xFFFDeadBeef00000L), 1.0, NaNd}, 82 {Double.longBitsToDouble(0x7FFCafeBabe00000L), 1.0, NaNd}, 83 {Double.longBitsToDouble(0xFFFCafeBabe00000L), 1.0, NaNd}, 84 }; 85 86 for(int i = 0; i < testCases.length; i++) { 87 failures += testHypotCase(testCases[i][0], testCases[i][1], 88 testCases[i][2]); 89 } 90 91 // Verify hypot(x, 0.0) is close to x over the entire exponent 92 // range. 93 for(int i = DoubleConsts.MIN_SUB_EXPONENT; 94 i <= Double.MAX_EXPONENT; 95 i++) { 96 double input = Math.scalb(2, i); 97 failures += testHypotCase(input, 0.0, input); 98 } 99 100 101 // Test Pythagorean triples 102 103 // Small ones 104 for(int m = 1; m < 10; m++) { 105 for(int n = m+1; n < 11; n++) { 106 long [] result = pythagoreanTriple(m, n); 107 failures += testHypotCase(result[0], result[1], result[2]); 108 } 109 } 110 111 // Big ones 112 for(int m = 100000; m < 100100; m++) { 113 for(int n = m+100000; n < 200200; n++) { 114 long [] result = pythagoreanTriple(m, n); 115 failures += testHypotCase(result[0], result[1], result[2]); 116 } 117 } 118 119 // Approaching overflow tests 120 121 /* 122 * Create a random value r with an large-ish exponent. The 123 * result of hypot(3*r, 4*r) should be approximately 5*r. (The 124 * computation of 4*r is exact since it just changes the 125 * exponent). While the exponent of r is less than or equal 126 * to (MAX_EXPONENT - 3), the computation should not overflow. 127 */ 128 java.util.Random rand = RandomFactory.getRandom(); 129 for(int i = 0; i < 1000; i++) { 130 double d = rand.nextDouble(); 131 // Scale d to have an exponent equal to MAX_EXPONENT -15 132 d = Math.scalb(d, Double.MAX_EXPONENT 133 -15 - Tests.ilogb(d)); 134 for(int j = 0; j <= 13; j += 1) { 135 failures += testHypotCase(3*d, 4*d, 5*d, 2.5); 136 d *= 2.0; // increase exponent by 1 137 } 138 } 139 140 // Test for monotonicity failures. Fix one argument and test 141 // two numbers before and two numbers after each chosen value; 142 // i.e. 143 // 144 // pcNeighbors[] = 145 // {nextDown(nextDown(pc)), 146 // nextDown(pc), 147 // pc, 148 // nextUp(pc), 149 // nextUp(nextUp(pc))} 150 // 151 // and we test that hypot(pcNeighbors[i]) <= hypot(pcNeighbors[i+1]) 152 { 153 double pcNeighbors[] = new double[5]; 154 double pcNeighborsHypot[] = new double[5]; 155 double pcNeighborsStrictHypot[] = new double[5]; 156 157 158 for(int i = -18; i <= 18; i++) { 159 double pc = Math.scalb(1.0, i); 160 161 pcNeighbors[2] = pc; 162 pcNeighbors[1] = Math.nextDown(pc); 163 pcNeighbors[0] = Math.nextDown(pcNeighbors[1]); 164 pcNeighbors[3] = Math.nextUp(pc); 165 pcNeighbors[4] = Math.nextUp(pcNeighbors[3]); 166 167 for(int j = 0; j < pcNeighbors.length; j++) { 168 pcNeighborsHypot[j] = Math.hypot(2.0, pcNeighbors[j]); 169 pcNeighborsStrictHypot[j] = StrictMath.hypot(2.0, pcNeighbors[j]); 170 } 171 172 for(int j = 0; j < pcNeighborsHypot.length-1; j++) { 173 if(pcNeighborsHypot[j] > pcNeighborsHypot[j+1] ) { 174 failures++; 175 System.err.println("Monotonicity failure for Math.hypot on " + 176 pcNeighbors[j] + " and " + 177 pcNeighbors[j+1] + "\n\treturned " + 178 pcNeighborsHypot[j] + " and " + 179 pcNeighborsHypot[j+1] ); 180 } 181 182 if(pcNeighborsStrictHypot[j] > pcNeighborsStrictHypot[j+1] ) { 183 failures++; 184 System.err.println("Monotonicity failure for StrictMath.hypot on " + 185 pcNeighbors[j] + " and " + 186 pcNeighbors[j+1] + "\n\treturned " + 187 pcNeighborsStrictHypot[j] + " and " + 188 pcNeighborsStrictHypot[j+1] ); 189 } 190 191 192 } 193 194 } 195 } 196 197 198 return failures; 199 } 200 201 static int testHypotCase(double input1, double input2, double expected) { 202 return testHypotCase(input1,input2, expected, 1); 203 } 204 205 static int testHypotCase(double input1, double input2, double expected, 206 double ulps) { 207 int failures = 0; 208 if (expected < 0.0) { 209 throw new AssertionError("Result of hypot must be greater than " + 210 "or equal to zero"); 211 } 212 213 // Test Math and StrictMath methods with no inputs negated, 214 // each input negated singly, and both inputs negated. Also 215 // test inputs in reversed order. 216 217 for(int i = -1; i <= 1; i+=2) { 218 for(int j = -1; j <= 1; j+=2) { 219 double x = i * input1; 220 double y = j * input2; 221 failures += Tests.testUlpDiff("Math.hypot", x, y, 222 Math.hypot(x, y), expected, ulps); 223 failures += Tests.testUlpDiff("Math.hypot", y, x, 224 Math.hypot(y, x ), expected, ulps); 225 226 failures += Tests.testUlpDiff("StrictMath.hypot", x, y, 227 StrictMath.hypot(x, y), expected, ulps); 228 failures += Tests.testUlpDiff("StrictMath.hypot", y, x, 229 StrictMath.hypot(y, x), expected, ulps); 230 } 231 } 232 233 return failures; 234 } 235 236 public static void main(String argv[]) { 237 int failures = 0; 238 239 failures += testHypot(); 240 241 if (failures > 0) { 242 System.err.println("Testing the hypot incurred " 243 + failures + " failures."); 244 throw new RuntimeException(); 245 } 246 } 247 248} 249