1 /*
   2  * Copyright (c) 2011, 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  * @bug 4900206
  27  * @summary Test worst case behavior of exp, log, sin, cos, etc.
  28  * @author Joseph D. Darcy
  29  */
  30 
  31 /**
  32  * Use "Table Maker's Dilemma" results from Jean-Michel Muller et
  33  * al. to test the math library.  See
  34  * http://perso.ens-lyon.fr/jean-michel.muller/TMD.html for original
  35  * numbers and more information about the methodology of producing
  36  * these test vectors.
  37  *
  38  * The Java math libraries methods in question have a 1-ulp error
  39  * bound from their specifications.  This implies the returned value
  40  * must be one of the two representable floating-point numbers
  41  * bracketing the exact result.  The expected value in the test
  42  * vectors below is the trunction of the exact value.  Therefore, the
  43  * computed result must either be that value or the value next larger
  44  * in magnitude.
  45  */
  46 public class WorstCaseTests {
  47     private WorstCaseTests() {throw new AssertionError("No instances for you.");}
  48 
  49     public static void main(String... args) {
  50         int failures = 0;
  51 
  52         failures += testWorstExp();
  53         failures += testWorstLog();
  54         failures += testWorstSin();
  55         failures += testWorstAsin();
  56         failures += testWorstCos();
  57         failures += testWorstAcos();
  58         failures += testWorstTan();
  59         failures += testWorstAtan();
  60         failures += testWorstPow2();
  61 
  62         if (failures > 0) {
  63             System.err.printf("Testing worst cases incurred %d failures.%n", failures);
  64             throw new RuntimeException();
  65         }
  66     }
  67 
  68     /**
  69      * Return the floating-point value next larger in magnitude.
  70      */
  71     private static double nextOut(double d) {
  72         if (d > 0.0)
  73             return Math.nextUp(d);
  74         else
  75             return -Math.nextUp(-d);
  76     }
  77 
  78     private static int testWorstExp() {
  79         int failures = 0;
  80         double [][] testCases = {
  81             {-0x1.E8BDBFCD9144Ep3,      0x1.F3E558CF4DE54p-23},
  82             {-0x1.71E0B869B5E79p2,      0x1.951C6DC5D24E2p-9},
  83             {-0x1.02393D5976769p1,      0x1.1064B2C103DDAp-3},
  84             {-0x1.2A9CAD9998262p0,      0x1.3EF1E9B3A81C7p-2},
  85             {-0x1.CC37EF7DE7501p0,      0x1.534D4DE870713p-3},
  86             {-0x1.22E24FA3D5CF9p-1,     0x1.2217147B85EA9p-1},
  87             {-0x1.DC2B5DF1F7D3Dp-1,     0x1.9403FD0EE51C8p-2},
  88             {-0x1.290EA09E36479p-3,     0x1.BADED30CBF1C3p-1},
  89             {-0x1.A2FEFEFD580DFp-13,    0x1.FFE5D0BB7EABFp-1},
  90             {-0x1.ED318EFB627EAp-27,    0x1.FFFFFF84B39C4p-1},
  91             {-0x1.4BD46601AE1EFp-31,    0x1.FFFFFFFAD0AE6p-1},
  92             {-0x1.1000000000242p-42,    0x1.FFFFFFFFFF780p-1},
  93             {-0x1.2000000000288p-42,    0x1.FFFFFFFFFF700p-1},
  94             {-0x1.8000000000012p-48,    0x1.FFFFFFFFFFFD0p-1},
  95             {-0x1.0000000000001p-51,    0x1.FFFFFFFFFFFFCp-1},
  96 
  97             {+0x1.FFFFFFFFFFFFFp-53,    0x1.0000000000000p0},
  98             {+0x1.FFFFFFFFFFFE0p-48,    0x1.000000000001Fp0},
  99             {+0x1.7FFE7FFEE0024p-32,    0x1.000000017FFE8p0},
 100             {+0x1.80017FFEDFFDCp-32,    0x1.0000000180017p0},
 101             {+0x1.9E9CBBFD6080Bp-31,    0x1.000000033D397p0},
 102             {+0x1.D7A7D893609E5p-26,    0x1.00000075E9F64p0},
 103             {+0x1.BA07D73250DE7p-14,    0x1.0006E83736F8Cp0},
 104             {+0x1.D77FD13D27FFFp-11,    0x1.003AF6C37C1D3p0},
 105             {+0x1.6A4D1AF9CC989p-8,     0x1.016B4DF3299D7p0},
 106             {+0x1.ACCFBE46B4EF0p-1,     0x2.4F85C9783DCE0p0},
 107             {+0x1.ACA7AE8DA5A7Bp0,      0x5.55F52B35F955Ap0},
 108             {+0x1.D6336A88077AAp0,      0x6.46A37FD503FDCp0},
 109             {+0x2.85DC78FB8928Cp0,      0xC.76F2496CB038Fp0},
 110             {+0x1.76E7E5D7B6EACp3,      0x1.DE7CD6751029Ap16},
 111             {+0x1.A8EAD058BC6B8p3,      0x1.1D71965F516ADp19},
 112             {+0x1.1D5C2DAEBE367p4,      0x1.A8C02E974C314p25},
 113             {+0x1.C44CE0D716A1Ap4,      0x1.B890CA8637AE1p40},
 114         };
 115 
 116         for(double[] testCase: testCases) {
 117             failures += testExpCase(testCase[0], testCase[1]);
 118         }
 119 
 120         return failures;
 121     }
 122 
 123     private static int testExpCase(double input, double expected) {
 124         int failures = 0;
 125         double out = nextOut(expected);
 126         failures += Tests.testBounds("Math.exp",       input, Math.exp(input),       expected, out);
 127         failures += Tests.testBounds("StrictMath.exp", input, StrictMath.exp(input), expected, out);
 128         return failures;
 129     }
 130 
 131     private static int testWorstLog() {
 132         int failures = 0;
 133         double [][] testCases = {
 134             {+0x1.0000000000001p0,      +0x1.FFFFFFFFFFFFFp-53},
 135             {+0x2.0012ECB039C9Cp0,      +0x1.62F71C4656B60p-1},
 136             {+0x6.46A37FD503FDCp0,      +0x1.D6336A88077A9p+0},
 137             {+0x7.78DFECC7F57Fp0,       +0x2.02DD059DB46Bp+0},
 138             {+0x9.588CCF24BB9C8p0,      +0x2.3C24DEBB2BE7p+0},
 139             {+0xA.AF87550D97E4p0,       +0x2.5E706595A7ABEp+0},
 140             {+0xC.76F2496CB039p0,       +0x2.85DC78FB8928Cp+0},
 141             {+0x11.1867637CBD03p0,      +0x2.D6BBEFC79A842p+0},
 142             {+0x13.D9D7D597A9DDp0,      +0x2.FCFE12AE07DDCp+0},
 143             {+0x17.F3825778AAAFp0,      +0x3.2D0F907F5E00Cp+0},
 144             {+0x1AC.50B409C8AEEp0,      +0x6.0F52F37AECFCCp+0},
 145             {+0x1.DE7CD6751029Ap16,     +0x1.76E7E5D7B6EABp+3},
 146         };
 147 
 148         for(double[] testCase: testCases) {
 149             failures += testLogCase(testCase[0], testCase[1]);
 150         }
 151 
 152         return failures;
 153     }
 154 
 155     private static int testLogCase(double input, double expected) {
 156         int failures = 0;
 157         double out = nextOut(expected);
 158         failures += Tests.testBounds("Math.log",       input, Math.log(input),       expected, out);
 159         failures += Tests.testBounds("StrictMath.log", input, StrictMath.log(input), expected, out);
 160         return failures;
 161     }
 162 
 163     private static int testWorstSin() {
 164         int failures = 0;
 165         double [][] testCases = {
 166             {+0x1.9283586503FEp-5,      +0x1.9259E3708BD39p-5},
 167             {+0x1.D7BDCD778049Fp-5,     +0x1.D77B117F230D5p-5},
 168             {+0x1.A202B3FB84788p-4,     +0x1.A1490C8C06BA6p-4},
 169             {+0x1.D037CB27EE6DFp-3,     +0x1.CC40C3805229Ap-3},
 170             {+0x1.D5064E6FE82C5p-3,     +0x1.D0EF799001BA9p-3},
 171             {+0x1.FE767739D0F6Dp-2,     +0x1.E9950730C4695p-2},
 172             {+0x1.D98C4C612718Dp-1,     +0x1.98DCD09337792p-1},
 173             {+0x1.921FB54442D18p-0,     +0x1.FFFFFFFFFFFFFp-1},
 174         };
 175 
 176         for(double[] testCase: testCases) {
 177             failures += testSinCase(testCase[0], testCase[1]);
 178         }
 179 
 180         return failures;
 181     }
 182 
 183     private static int testSinCase(double input, double expected) {
 184         int failures = 0;
 185         double out = nextOut(expected);
 186         failures += Tests.testBounds("Math.sin",       input, Math.sin(input),       expected, out);
 187         failures += Tests.testBounds("StrictMath.sin", input, StrictMath.sin(input), expected, out);
 188         return failures;
 189     }
 190 
 191     private static int testWorstAsin() {
 192         int failures = 0;
 193         double [][] testCases = {
 194             {+0x1.9259E3708BD3Ap-5,     +0x1.9283586503FEp-5},
 195             {+0x1.D77B117F230D6p-5,     +0x1.D7BDCD778049Fp-5},
 196             {+0x1.A1490C8C06BA7p-4,     +0x1.A202B3FB84788p-4},
 197             {+0x1.9697CB602C582p-3,     +0x1.994FFB5DAF0F9p-3},
 198             {+0x1.D0EF799001BA9p-3,     +0x1.D5064E6FE82C4p-3},
 199             {+0x1.E9950730C4696p-2,     +0x1.FE767739D0F6Dp-2},
 200             {+0x1.1ED06D50F7E88p-1,     +0x1.30706F699466Dp-1},
 201             {+0x1.D5B05A89D3E77p-1,     +0x1.29517AB4C132Ap+0},
 202             {+0x1.E264357EA0E29p-1,     +0x1.3AA301F6EBB1Dp+0},
 203         };
 204 
 205         for(double[] testCase: testCases) {
 206             failures += testAsinCase(testCase[0], testCase[1]);
 207         }
 208 
 209         return failures;
 210     }
 211 
 212     private static int testAsinCase(double input, double expected) {
 213         int failures = 0;
 214         double out = nextOut(expected);
 215         failures += Tests.testBounds("Math.asin",       input, Math.asin(input),       expected, out);
 216         failures += Tests.testBounds("StrictMath.asin", input, StrictMath.asin(input), expected, out);
 217         return failures;
 218     }
 219 
 220     private static int testWorstCos() {
 221         int failures = 0;
 222         double [][] testCases = {
 223             {+0x1.549EC0C0C5AFAp-5,     +0x1.FF8EB6A91ECB0p-1},
 224             {+0x1.16E534EE36580p-4,     +0x1.FED0476FC75C9p-1},
 225             {+0x1.EFEEF61D39AC2p-3,     +0x1.F10FC61E2C78Ep-1},
 226             {+0x1.FEB1F7920E248p-2,     +0x1.C1A27AE836F12p-1},
 227             {+0x1.7CB7648526F99p-1,     +0x1.78DAF01036D0Cp-1},
 228             {+0x1.C65A170474549p-1,     +0x1.434A3645BE208p-1},
 229             {+0x1.6B8A6273D7C21p+0,     +0x1.337FC5B072C52p-3},
 230         };
 231 
 232         for(double[] testCase: testCases) {
 233             failures += testCosCase(testCase[0], testCase[1]);
 234         }
 235 
 236         return failures;
 237     }
 238 
 239     private static int testCosCase(double input, double expected) {
 240         int failures = 0;
 241         double out = nextOut(expected);
 242         failures += Tests.testBounds("Math.cos",       input, Math.cos(input),       expected, out);
 243         failures += Tests.testBounds("StrictMath.cos", input, StrictMath.cos(input), expected, out);
 244         return failures;
 245     }
 246 
 247     private static int testWorstAcos() {
 248         int failures = 0;
 249         double [][] testCases = {
 250             {+0x1.FD737BE914578p-11,    +0x1.91E006D41D8D8p+0},
 251             {+0x1.4182199998587p-1,     +0x1.C8A538AE83D1Fp-1},
 252             {+0x1.E45A1C93651ECp-1,     +0x1.520DC553F6B23p-2},
 253             {+0x1.F10FC61E2C78Fp-1,     +0x1.EFEEF61D39AC1p-3},
 254         };
 255 
 256         for(double[] testCase: testCases) {
 257             failures += testAcosCase(testCase[0], testCase[1]);
 258         }
 259 
 260         return failures;
 261     }
 262 
 263     private static int testAcosCase(double input, double expected) {
 264         int failures = 0;
 265         double out = nextOut(expected);
 266         failures += Tests.testBounds("Math.acos",       input, Math.acos(input),       expected, out);
 267         failures += Tests.testBounds("StrictMath.acos", input, StrictMath.acos(input), expected, out);
 268         return failures;
 269     }
 270 
 271     private static int testWorstTan() {
 272         int failures = 0;
 273         double [][] testCases = {
 274             {+0x1.50486B2F87014p-5,     +0x1.5078CEBFF9C72p-5},
 275             {+0x1.52C39EF070CADp-4,     +0x1.5389E6DF41978p-4},
 276             {+0x1.A33F32AC5CEB5p-3,     +0x1.A933FE176B375p-3},
 277             {+0x1.D696BFA988DB9p-2,     +0x1.FAC71CD34EEA6p-2},
 278             {+0x1.46AC372243536p-1,     +0x1.7BA49F739829Ep-1},
 279         };
 280 
 281         for(double[] testCase: testCases) {
 282             failures += testTanCase(testCase[0], testCase[1]);
 283         }
 284 
 285         return failures;
 286     }
 287 
 288     private static int testTanCase(double input, double expected) {
 289         int failures = 0;
 290         double out = nextOut(expected);
 291         failures += Tests.testBounds("Math.tan",       input, Math.tan(input),       expected, out);
 292         failures += Tests.testBounds("StrictMath.tan", input, StrictMath.tan(input), expected, out);
 293         return failures;
 294     }
 295 
 296     private static int testWorstAtan() {
 297         int failures = 0;
 298         double [][] testCases = {
 299             {+0x1.0FC9F1FABE658p-5,     +0x1.0FB06EDE9973Ap-5},
 300             {+0x1.1BBE9C255698Dp-5,     +0x1.1BA1951DB1D6Dp-5},
 301             {+0x1.8DDD25AB90CA1p-5,     +0x1.8D8D2D4BD6FA2p-5},
 302             {+0x1.5389E6DF41979p-4,     +0x1.52C39EF070CADp-4},
 303             {+0x1.A933FE176B375p-3,     +0x1.A33F32AC5CEB4p-3},
 304             {+0x1.0F6E5D9960397p-2,     +0x1.09544B71AD4A6p-2},
 305             {+0x1.7BA49F739829Fp-1,     +0x1.46AC372243536p-1},
 306         };
 307 
 308         for(double[] testCase: testCases) {
 309             failures += testAtanCase(testCase[0], testCase[1]);
 310         }
 311 
 312         return failures;
 313     }
 314 
 315     private static int testAtanCase(double input, double expected) {
 316         int failures = 0;
 317         double out = nextOut(expected);
 318         failures += Tests.testBounds("Math.atan",       input, Math.atan(input),       expected, out);
 319         failures += Tests.testBounds("StrictMath.atan", input, StrictMath.atan(input), expected, out);
 320         return failures;
 321     }
 322 
 323     private static int testWorstPow2() {
 324         int failures = 0;
 325         double [][] testCases = {
 326             {+0x1.16A76EC41B516p-1,     +0x1.7550685A42C63p+0},
 327             {+0x1.3E34FA6AB969Ep-1,     +0x1.89D948A94FE16p+0},
 328             {+0x1.4A63FF1D53F53p-1,     +0x1.90661DA12D528p+0},
 329             {+0x1.B32A6C92D1185p-1,     +0x1.CD6B37EDECEAFp+0},
 330 
 331             {+0x1.25DD9EEDAC79Ap+0,     +0x1.1BA39FF28E3E9p+1},
 332         };
 333 
 334         for(double[] testCase: testCases) {
 335             failures += testPow2Case(testCase[0], testCase[1]);
 336         }
 337 
 338         return failures;
 339     }
 340 
 341     private static int testPow2Case(double input, double expected) {
 342         int failures = 0;
 343         double out = nextOut(expected);
 344         failures += Tests.testBounds("Math.pow2",       input, Math.pow(2, input),       expected, out);
 345         failures += Tests.testBounds("StrictMath.pow2", input, StrictMath.pow(2, input), expected, out);
 346         return failures;
 347     }
 348 }