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 
24 /*
25  * Shared static test methods for numerical tests.  Sharing these
26  * helper test methods avoids repeated functions in the various test
27  * programs.  The test methods return 1 for a test failure and 0 for
28  * success.  The order of arguments to the test methods is generally
29  * the test name, followed by the test arguments, the computed result,
30  * and finally the expected result.
31  */
32 package test.java.lang.Math;
33 
34 import org.testng.annotations.Test;
35 import org.testng.Assert;
36 
37 public class Tests {
38 
Tests()39     private Tests() {
40     }
41 
42     ; // do not instantiate
43 
toHexString(float f)44     public static String toHexString(float f) {
45         if (!Float.isNaN(f)) {
46             return Float.toHexString(f);
47         } else {
48             return "NaN(0x" + Integer.toHexString(Float.floatToRawIntBits(f)) + ")";
49         }
50     }
51 
toHexString(double d)52     public static String toHexString(double d) {
53         if (!Double.isNaN(d)) {
54             return Double.toHexString(d);
55         } else {
56             return "NaN(0x" + Long.toHexString(Double.doubleToRawLongBits(d)) + ")";
57         }
58     }
59 
60     /**
61      * Return the floating-point value next larger in magnitude.
62      */
nextOut(double d)63     public static double nextOut(double d) {
64         if (d > 0.0) {
65             return Math.nextUp(d);
66         } else {
67             return -Math.nextUp(-d);
68         }
69     }
70 
71     /**
72      * Returns unbiased exponent of a {@code float}; for subnormal values, the number is treated as
73      * if it were normalized.  That is for all finite, non-zero, positive numbers
74      * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is
75      * always in the range [1, 2).
76      * <p>
77      * Special cases:
78      * <ul>
79      * <li> If the argument is NaN, then the result is 2<sup>30</sup>.
80      * <li> If the argument is infinite, then the result is 2<sup>28</sup>.
81      * <li> If the argument is zero, then the result is -(2<sup>28</sup>).
82      * </ul>
83      *
84      * @param d double number which exponent is to be extracted
85      * @return unbiased exponent of the argument.
86      */
ilogb(double d)87     public static int ilogb(double d) {
88         int exponent = Math.getExponent(d);
89 
90         switch (exponent) {
91             case Double.MAX_EXPONENT + 1:       // NaN or infinity
92                 if (Double.isNaN(d)) {
93                     return (1 << 30);         // 2^30
94                 } else // infinite value
95                 {
96                     return (1 << 28);         // 2^28
97                 }
98 
99             case Double.MIN_EXPONENT - 1:       // zero or subnormal
100                 if (d == 0.0) {
101                     return -(1 << 28);        // -(2^28)
102                 } else {
103                     long transducer = Double.doubleToRawLongBits(d);
104 
105                     /*
106                      * To avoid causing slow arithmetic on subnormals,
107                      * the scaling to determine when d's significand
108                      * is normalized is done in integer arithmetic.
109                      * (there must be at least one "1" bit in the
110                      * significand since zero has been screened out.
111                      */
112 
113                     // isolate significand bits
114                     transducer &= DoubleConsts.SIGNIF_BIT_MASK;
115                     Assert.assertNotEquals(transducer, 0L);
116 
117                     // This loop is simple and functional. We might be
118                     // able to do something more clever that was faster;
119                     // e.g. number of leading zero detection on
120                     // (transducer << (# exponent and sign bits).
121                     while (transducer <
122                             (1L << (DoubleConsts.SIGNIFICAND_WIDTH - 1))) {
123                         transducer *= 2;
124                         exponent--;
125                     }
126                     exponent++;
127                     Assert.assertTrue(exponent >=
128                             Double.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH - 1) &&
129                             exponent < Double.MIN_EXPONENT);
130                     return exponent;
131                 }
132 
133             default:
134                 Assert.assertTrue(exponent >= Double.MIN_EXPONENT &&
135                         exponent <= Double.MAX_EXPONENT);
136                 return exponent;
137         }
138     }
139 
140     /**
141      * Returns unbiased exponent of a {@code float}; for subnormal values, the number is treated as
142      * if it were normalized.  That is for all finite, non-zero, positive numbers
143      * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is
144      * always in the range [1, 2).
145      * <p>
146      * Special cases:
147      * <ul>
148      * <li> If the argument is NaN, then the result is 2<sup>30</sup>.
149      * <li> If the argument is infinite, then the result is 2<sup>28</sup>.
150      * <li> If the argument is zero, then the result is -(2<sup>28</sup>).
151      * </ul>
152      *
153      * @param f floating-point number whose exponent is to be extracted
154      * @return unbiased exponent of the argument.
155      */
ilogb(float f)156     public static int ilogb(float f) {
157         int exponent = Math.getExponent(f);
158 
159         switch (exponent) {
160             case Float.MAX_EXPONENT + 1:        // NaN or infinity
161                 if (Float.isNaN(f)) {
162                     return (1 << 30);         // 2^30
163                 } else // infinite value
164                 {
165                     return (1 << 28);         // 2^28
166                 }
167 
168             case Float.MIN_EXPONENT - 1:        // zero or subnormal
169                 if (f == 0.0f) {
170                     return -(1 << 28);        // -(2^28)
171                 } else {
172                     int transducer = Float.floatToRawIntBits(f);
173 
174                     /*
175                      * To avoid causing slow arithmetic on subnormals,
176                      * the scaling to determine when f's significand
177                      * is normalized is done in integer arithmetic.
178                      * (there must be at least one "1" bit in the
179                      * significand since zero has been screened out.
180                      */
181 
182                     // isolate significand bits
183                     transducer &= FloatConsts.SIGNIF_BIT_MASK;
184                     Assert.assertNotEquals(transducer, 0L);
185 
186                     // This loop is simple and functional. We might be
187                     // able to do something more clever that was faster;
188                     // e.g. number of leading zero detection on
189                     // (transducer << (# exponent and sign bits).
190                     while (transducer <
191                             (1 << (FloatConsts.SIGNIFICAND_WIDTH - 1))) {
192                         transducer *= 2;
193                         exponent--;
194                     }
195                     exponent++;
196                     Assert.assertTrue(exponent >=
197                             Float.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH - 1) &&
198                             exponent < Float.MIN_EXPONENT);
199                     return exponent;
200                 }
201 
202             default:
203                 Assert.assertTrue(exponent >= Float.MIN_EXPONENT &&
204                         exponent <= Float.MAX_EXPONENT);
205                 return exponent;
206         }
207     }
208 
209     /**
210      * Returns {@code true} if the unordered relation holds between the two arguments.  When two
211      * floating-point values are unordered, one value is neither less than, equal to, nor greater
212      * than the other.  For the unordered relation to be true, at least one argument must be a
213      * {@code NaN}.
214      *
215      * @param arg1 the first argument
216      * @param arg2 the second argument
217      * @return {@code true} if at least one argument is a NaN, {@code false} otherwise.
218      */
isUnordered(float arg1, float arg2)219     public static boolean isUnordered(float arg1, float arg2) {
220         return Float.isNaN(arg1) || Float.isNaN(arg2);
221     }
222 
223     /**
224      * Returns {@code true} if the unordered relation holds between the two arguments.  When two
225      * floating-point values are unordered, one value is neither less than, equal to, nor greater
226      * than the other.  For the unordered relation to be true, at least one argument must be a
227      * {@code NaN}.
228      *
229      * @param arg1 the first argument
230      * @param arg2 the second argument
231      * @return {@code true} if at least one argument is a NaN, {@code false} otherwise.
232      */
isUnordered(double arg1, double arg2)233     public static boolean isUnordered(double arg1, double arg2) {
234         return Double.isNaN(arg1) || Double.isNaN(arg2);
235     }
236 
test(String testName, float input, boolean result, boolean expected)237     public static void test(String testName, float input,
238             boolean result, boolean expected) {
239         Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" +
240                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
241                 "\texpected  " + expected + "\n" +
242                 "\tgot       " + result + ").");
243     }
244 
test(String testName, double input, boolean result, boolean expected)245     public static void test(String testName, double input,
246             boolean result, boolean expected) {
247         Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" +
248                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
249                 "\texpected  " + expected + "\n" +
250                 "\tgot       " + result + ").");
251     }
252 
test(String testName, float input1, float input2, boolean result, boolean expected)253     public static void test(String testName, float input1, float input2,
254             boolean result, boolean expected) {
255         Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" +
256                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
257                 + input2 + "\t(" + toHexString(input2) + ")\n" +
258                 "\texpected  " + expected + "\n" +
259                 "\tgot       " + result + ").");
260     }
261 
test(String testName, double input1, double input2, boolean result, boolean expected)262     public static void test(String testName, double input1, double input2,
263             boolean result, boolean expected) {
264         Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" +
265                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
266                 + input2 + "\t(" + toHexString(input2) + ")\n" +
267                 "\texpected  " + expected + "\n" +
268                 "\tgot       " + result + ").");
269     }
270 
test(String testName, float input, int result, int expected)271     public static void test(String testName, float input,
272             int result, int expected) {
273         Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" +
274                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
275                 "\texpected  " + expected + "\n" +
276                 "\tgot       " + result + ").");
277     }
278 
test(String testName, double input, int result, int expected)279     public static void test(String testName, double input,
280             int result, int expected) {
281         Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" +
282                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
283                 "\texpected  " + expected + "\n" +
284                 "\tgot       " + result + ").");
285     }
286 
test(String testName, float input, float result, float expected)287     public static void test(String testName, float input,
288             float result, float expected) {
289         Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" +
290                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
291                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
292                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
293     }
294 
295 
test(String testName, double input, double result, double expected)296     public static void test(String testName, double input,
297             double result, double expected) {
298         Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" +
299                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
300                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
301                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
302     }
303 
test(String testName, float input1, double input2, float result, float expected)304     public static void test(String testName,
305             float input1, double input2,
306             float result, float expected) {
307         Assert.assertEquals(Float.compare(expected, result), 0, "Failure for " + testName + ":\n" +
308                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
309                 + input2 + "\t(" + toHexString(input2) + ")\n" +
310                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
311                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
312     }
313 
test(String testName, double input1, double input2, double result, double expected)314     public static void test(String testName,
315             double input1, double input2,
316             double result, double expected) {
317         Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" +
318                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
319                 + input2 + "\t(" + toHexString(input2) + ")\n" +
320                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
321                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
322     }
323 
test(String testName, float input1, int input2, float result, float expected)324     public static void test(String testName,
325             float input1, int input2,
326             float result, float expected) {
327         Assert.assertEquals(Float.compare(expected, result), 0, "Failure for " + testName + ":\n" +
328                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
329                 + input2 + "\n" +
330                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
331                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
332     }
333 
test(String testName, double input1, int input2, double result, double expected)334     public static void test(String testName,
335             double input1, int input2,
336             double result, double expected) {
337         Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" +
338                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
339                 + input2 + "\n" +
340                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
341                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
342     }
343 
test(String testName, float input1, float input2, float input3, float result, float expected)344     public static void test(String testName,
345             float input1, float input2, float input3,
346             float result, float expected) {
347         Assert.assertEquals(Float.compare(expected, result), 0, "Failure for " + testName + ":\n" +
348                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
349                 + input2 + "\t(" + toHexString(input2) + ") and"
350                 + input3 + "\t(" + toHexString(input3) + ")\n" +
351                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
352                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
353     }
354 
test(String testName, double input1, double input2, double input3, double result, double expected)355     public static void test(String testName,
356             double input1, double input2, double input3,
357             double result, double expected) {
358         Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" +
359                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
360                 + input2 + "\t(" + toHexString(input2) + ") and"
361                 + input3 + "\t(" + toHexString(input3) + ")\n" +
362                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
363                 "\tgot       " + result + "\t(" + toHexString(result) + ").");
364     }
365 
testUlpCore(double result, double expected, double ulps)366     static int testUlpCore(double result, double expected, double ulps) {
367         // We assume we won't be unlucky and have an inexact expected
368         // be nextDown(2^i) when 2^i would be the correctly rounded
369         // answer.  This would cause the ulp size to be half as large
370         // as it should be, doubling the measured error).
371 
372         if (Double.compare(expected, result) == 0) {
373             return 0;   // result and expected are equivalent
374         } else {
375             if (ulps == 0.0) {
376                 // Equivalent results required but not found
377                 return 1;
378             } else {
379                 double difference = expected - result;
380                 if (isUnordered(expected, result) ||
381                         Double.isNaN(difference) ||
382                         // fail if greater than or unordered
383                         !(Math.abs(difference / Math.ulp(expected)) <= Math.abs(ulps))) {
384                     return 1;
385                 } else {
386                     return 0;
387                 }
388             }
389         }
390     }
391 
392     // One input argument.
testUlpDiff(String testName, double input, double result, double expected, double ulps)393     public static void testUlpDiff(String testName, double input,
394             double result, double expected, double ulps) {
395         int code = testUlpCore(result, expected, ulps);
396         Assert.assertEquals(code, 0, "Failure for " + testName + ":\n" +
397                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
398                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
399                 "\tgot       " + result + "\t(" + toHexString(result) + ");\n" +
400                 "\tdifference greater than ulp tolerance " + ulps);
401     }
402 
403     // Two input arguments.
testUlpDiff(String testName, double input1, double input2, double result, double expected, double ulps)404     public static void testUlpDiff(String testName, double input1, double input2,
405             double result, double expected, double ulps) {
406         int code = testUlpCore(result, expected, ulps);
407         Assert.assertEquals(code, 0, "Failure for " + testName + ":\n" +
408                 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and "
409                 + input2 + "\t(" + toHexString(input2) + ")\n" +
410                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
411                 "\tgot       " + result + "\t(" + toHexString(result) + ");\n" +
412                 "\tdifference greater than ulp tolerance " + ulps);
413     }
414 
415     // For a successful test, the result must be within the ulp bound of
416     // expected AND the result must have absolute value less than or
417     // equal to absBound.
testUlpDiffWithAbsBound(String testName, double input, double result, double expected, double ulps, double absBound)418     public static void testUlpDiffWithAbsBound(String testName, double input,
419             double result, double expected,
420             double ulps, double absBound) {
421         int code = 0;   // return code value
422 
423         if (!(StrictMath.abs(result) <= StrictMath.abs(absBound)) &&
424                 !Double.isNaN(expected)) {
425             code = 1;
426         } else {
427             code = testUlpCore(result, expected, ulps);
428         }
429 
430         Assert.assertEquals(code, 0, "Failure for " + testName + ":\n" +
431                 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
432                 "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
433                 "\tgot       " + result + "\t(" + toHexString(result) + ");\n" +
434                 "\tdifference greater than ulp tolerance " + ulps +
435                 " or the result has larger magnitude than " + absBound);
436     }
437 
438     // For a successful test, the result must be within the ulp bound of
439     // expected AND the result must have absolute value greater than
440     // or equal to the lowerBound.
testUlpDiffWithLowerBound(String testName, double input, double result, double expected, double ulps, double lowerBound)441     public static void testUlpDiffWithLowerBound(String testName, double input,
442             double result, double expected,
443             double ulps, double lowerBound) {
444         int code = 0;   // return code value
445 
446         if (!(result >= lowerBound) && !Double.isNaN(expected)) {
447             code = 1;
448         } else {
449             code = testUlpCore(result, expected, ulps);
450         }
451 
452         Assert.assertEquals(code, 0, "Failure for " + testName +
453                 ":\n" +
454                 "\tFor input " + input + "\t(" + toHexString(input) + ")" +
455                 "\n\texpected  " + expected + "\t(" + toHexString(expected) + ")" +
456                 "\n\tgot       " + result + "\t(" + toHexString(result) + ");" +
457                 "\ndifference greater than ulp tolerance " + ulps +
458                 " or result not greater than or equal to the bound " + lowerBound);
459     }
460 
testTolerance(String testName, double input, double result, double expected, double tolerance)461     public static void testTolerance(String testName, double input,
462             double result, double expected, double tolerance) {
463         if (Double.compare(expected, result) != 0) {
464             double difference = expected - result;
465             Assert.assertFalse(isUnordered(expected, result) ||
466                             Double.isNaN(difference) ||
467                             // fail if greater than or unordered
468                             !(Math.abs((difference) / expected) <= StrictMath.pow(10, -tolerance)),
469                     "Failure for " + testName + ":\n" +
470                             "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
471                             "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
472                             "\tgot       " + result + "\t(" + toHexString(result) + ");\n" +
473                             "\tdifference greater than tolerance 10^-" + tolerance);
474         }
475     }
476 
477     // For a successful test, the result must be within the upper and
478     // lower bounds.
testBounds(String testName, double input, double result, double bound1, double bound2)479     public static void testBounds(String testName, double input, double result,
480             double bound1, double bound2) {
481         if (!((result >= bound1 && result <= bound2) || (result <= bound1 && result >= bound2))) {
482             double lowerBound = Math.min(bound1, bound2);
483             double upperBound = Math.max(bound1, bound2);
484             Assert.fail("Failure for " + testName + ":\n" +
485                     "\tFor input " + input + "\t(" + toHexString(input) + ")\n" +
486                     "\tgot       " + result + "\t(" + toHexString(result) + ");\n" +
487                     "\toutside of range\n" +
488                     "\t[" + lowerBound + "\t(" + toHexString(lowerBound) + "), " +
489                     upperBound + "\t(" + toHexString(upperBound) + ")]");
490         }
491     }
492 }
493