1 /*
   2  * Copyright 2004 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4984407 5033578
  27  * @summary Tests for {Math, StrictMath}.pow
  28  * @compile -source 1.5 PowTests.java
  29  * @run main PowTests
  30  * @author Joseph D. Darcy
  31  */
  32 
  33 public class PowTests {
  34     private PowTests(){}
  35 
  36     static final double infinityD = Double.POSITIVE_INFINITY;
  37 
  38     static int testPowCase(double input1, double input2, double expected) {
  39         int failures = 0;
  40         failures += Tests.test("StrictMath.pow(double, double)", input1, input2,
  41                                StrictMath.pow(input1, input2), expected);
  42         failures += Tests.test("Math.pow(double, double)", input1, input2,
  43                                Math.pow(input1, input2), expected);
  44         return failures;
  45     }
  46 
  47 
  48     static int testStrictPowCase(double input1, double input2, double expected) {
  49         int failures = 0;
  50         failures += Tests.test("StrictMath.pow(double, double)", input1, input2,
  51                                StrictMath.pow(input1, input2), expected);
  52         return failures;
  53     }
  54 
  55     static int testNonstrictPowCase(double input1, double input2, double expected) {
  56         int failures = 0;
  57         failures += Tests.test("Math.pow(double, double)", input1, input2,
  58                                Math.pow(input1, input2), expected);
  59         return failures;
  60     }
  61 
  62     /*
  63      * Test for bad negation implementation.
  64      */
  65     static int testPow() {
  66         int failures = 0;
  67 
  68         double [][] testCases = {
  69             {-0.0,               3.0,   -0.0},
  70             {-0.0,               4.0,    0.0},
  71             {-infinityD,        -3.0,   -0.0},
  72             {-infinityD,        -4.0,    0.0},
  73         };
  74 
  75         for (double[] testCase : testCases) {
  76             failures+=testPowCase(testCase[0], testCase[1], testCase[2]);
  77         }
  78 
  79         return failures;
  80     }
  81 
  82     /*
  83      * Test cross-product of different kinds of arguments.
  84      */
  85     static int testCrossProduct() {
  86         int failures = 0;
  87 
  88         double testData[] = {
  89                                 Double.NEGATIVE_INFINITY,
  90 /* > -oo */                     -Double.MAX_VALUE,
  91 /**/                            (double)Long.MIN_VALUE,
  92 /**/                            (double) -((1L<<53)+2L),
  93 /**/                            (double) -((1L<<53)),
  94 /**/                            (double) -((1L<<53)-1L),
  95 /**/                            -((double)Integer.MAX_VALUE + 4.0),
  96 /**/                            (double)Integer.MIN_VALUE - 1.0,
  97 /**/                            (double)Integer.MIN_VALUE,
  98 /**/                            (double)Integer.MIN_VALUE + 1.0,
  99 /**/                            -Math.PI,
 100 /**/                            -3.0,
 101 /**/                            -Math.E,
 102 /**/                            -2.0,
 103 /**/                            -1.0000000000000004,
 104 /* < -1.0 */                    -1.0000000000000002, // nextAfter(-1.0, -oo)
 105                                 -1.0,
 106 /* > -1.0 */                    -0.9999999999999999, // nextAfter(-1.0, +oo)
 107 /* > -1.0 */                    -0.9999999999999998,
 108 /**/                            -0.5,
 109 /**/                            -1.0/3.0,
 110 /* < 0.0 */                     -Double.MIN_VALUE,
 111                                 -0.0,
 112                                 +0.0,
 113 /* > 0.0 */                     +Double.MIN_VALUE,
 114 /**/                            +1.0/3.0,
 115 /**/                            +0.5,
 116 /**/                            +0.9999999999999998,
 117 /* < +1.0 */                    +0.9999999999999999, // nextAfter(-1.0, +oo)
 118                                 +1.0,
 119 /* > 1.0 */                     +1.0000000000000002, // nextAfter(+1.0, +oo)
 120 /**/                            +1.0000000000000004,
 121 /**/                            +2.0,
 122 /**/                            +Math.E,
 123 /**/                            +3.0,
 124 /**/                            +Math.PI,
 125 /**/                            -(double)Integer.MIN_VALUE - 1.0,
 126 /**/                            -(double)Integer.MIN_VALUE,
 127 /**/                            -(double)Integer.MIN_VALUE + 1.0,
 128 /**/                            (double)Integer.MAX_VALUE + 4.0,
 129 /**/                            (double) ((1L<<53)-1L),
 130 /**/                            (double) ((1L<<53)),
 131 /**/                            (double) ((1L<<53)+2L),
 132 /**/                            -(double)Long.MIN_VALUE,
 133 /* < oo */                      Double.MAX_VALUE,
 134                                 Double.POSITIVE_INFINITY,
 135                                 Double.NaN
 136     };
 137 
 138         double NaN = Double.NaN;
 139         for(double x: testData) {
 140             for(double y: testData) {
 141                 boolean testPass = false;
 142                 double expected=NaN;
 143                 double actual;
 144 
 145                 // First, switch on y
 146                 if( Double.isNaN(y)) {
 147                     expected = NaN;
 148                 } else if (y == 0.0) {
 149                     expected = 1.0;
 150                 } else if (Double.isInfinite(y) ) {
 151                     if(y > 0) { // x ^ (+oo)
 152                         if (Math.abs(x) > 1.0) {
 153                             expected = Double.POSITIVE_INFINITY;
 154                         } else if (Math.abs(x) == 1.0) {
 155                             expected = NaN;
 156                         } else if (Math.abs(x) < 1.0) {
 157                             expected = +0.0;
 158                         } else { // x is NaN
 159                             assert Double.isNaN(x);
 160                             expected = NaN;
 161                         }
 162                     } else { // x ^ (-oo)
 163                         if (Math.abs(x) > 1.0) {
 164                             expected = +0.0;
 165                         } else if (Math.abs(x) == 1.0) {
 166                             expected = NaN;
 167                         } else if (Math.abs(x) < 1.0) {
 168                             expected = Double.POSITIVE_INFINITY;
 169                         } else { // x is NaN
 170                             assert Double.isNaN(x);
 171                             expected = NaN;
 172                         }
 173                     } /* end Double.isInfinite(y) */
 174                 } else if (y == 1.0) {
 175                     expected = x;
 176                 } else if (Double.isNaN(x)) { // Now start switching on x
 177                     assert y != 0.0;
 178                     expected = NaN;
 179                 } else if (x == Double.NEGATIVE_INFINITY) {
 180                     expected = (y < 0.0) ? f2(y) :f1(y);
 181                 } else if (x == Double.POSITIVE_INFINITY) {
 182                     expected = (y < 0.0) ? +0.0 : Double.POSITIVE_INFINITY;
 183                 } else if (equivalent(x, +0.0)) {
 184                     assert y != 0.0;
 185                     expected = (y < 0.0) ? Double.POSITIVE_INFINITY: +0.0;
 186                 } else if (equivalent(x, -0.0)) {
 187                     assert y != 0.0;
 188                     expected = (y < 0.0) ? f1(y): f2(y);
 189                 } else if( x < 0.0) {
 190                     assert y != 0.0;
 191                     failures += testStrictPowCase(x, y, f3(x, y));
 192                     failures += testNonstrictPowCase(x, y, f3ns(x, y));
 193                     continue;
 194                 } else {
 195                     // go to next iteration
 196                     expected = NaN;
 197                     continue;
 198                 }
 199 
 200                 failures += testPowCase(x, y, expected);
 201             } // y
 202         } // x
 203         return failures;
 204     }
 205 
 206     static boolean equivalent(double a, double b) {
 207         return Double.compare(a, b) == 0;
 208     }
 209 
 210     static double f1(double y) {
 211         return (intClassify(y) == 1)?
 212             Double.NEGATIVE_INFINITY:
 213             Double.POSITIVE_INFINITY;
 214     }
 215 
 216 
 217     static double f2(double y) {
 218         return (intClassify(y) == 1)?-0.0:0.0;
 219     }
 220 
 221     static double f3(double x, double y) {
 222         switch( intClassify(y) ) {
 223         case 0:
 224             return StrictMath.pow(Math.abs(x), y);
 225             // break;
 226 
 227         case 1:
 228             return -StrictMath.pow(Math.abs(x), y);
 229             // break;
 230 
 231         case -1:
 232             return Double.NaN;
 233             // break;
 234 
 235         default:
 236             throw new AssertionError("Bad classification.");
 237             // break;
 238         }
 239     }
 240 
 241     static double f3ns(double x, double y) {
 242         switch( intClassify(y) ) {
 243         case 0:
 244             return Math.pow(Math.abs(x), y);
 245             // break;
 246 
 247         case 1:
 248             return -Math.pow(Math.abs(x), y);
 249             // break;
 250 
 251         case -1:
 252             return Double.NaN;
 253             // break;
 254 
 255         default:
 256             throw new AssertionError("Bad classification.");
 257             // break;
 258         }
 259     }
 260 
 261     static boolean isFinite(double a) {
 262         return (0.0*a  == 0);
 263     }
 264 
 265     /**
 266      * Return classification of argument: -1 for non-integers, 0 for
 267      * even integers, 1 for odd integers.
 268      */
 269     static int intClassify(double a) {
 270         if(!isFinite(a) || // NaNs and infinities
 271            (a != Math.floor(a) )) { // only integers are fixed-points of floor
 272                 return -1;
 273         }
 274         else {
 275             // Determine if argument is an odd or even integer.
 276 
 277             a = StrictMath.abs(a); // absolute value doesn't affect odd/even
 278 
 279             if(a+1.0 == a) { // a > maximum odd floating-point integer
 280                 return 0; // Large integers are all even
 281             }
 282             else { // Convert double -> long and look at low-order bit
 283                 long ell = (long)  a;
 284                 return ((ell & 0x1L) == (long)1)?1:0;
 285             }
 286         }
 287     }
 288 
 289     public static void main(String [] argv) {
 290         int failures = 0;
 291 
 292         failures += testPow();
 293         failures += testCrossProduct();
 294 
 295         if (failures > 0) {
 296             System.err.println("Testing pow incurred "
 297                                + failures + " failures.");
 298             throw new RuntimeException();
 299         }
 300     }
 301 }