1 /*
2  * Copyright (c) 2003, 2012, 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 4074599 4939441
27  * @summary Tests for {Math, StrictMath}.log10
28  * @author Joseph D. Darcy
29  */
30 package test.java.lang.Math;
31 
32 import org.testng.annotations.Test;
33 import org.testng.Assert;
34 
35 public class Log10Tests {
36 
Log10Tests()37     private Log10Tests() {
38     }
39 
40     static final double infinityD = Double.POSITIVE_INFINITY;
41     static final double NaNd = Double.NaN;
42     static final double LN_10 = StrictMath.log(10.0);
43 
44     // Initialize shared random number generator
45     static java.util.Random rand = new java.util.Random(0L);
46 
testLog10Case(double input, double expected)47     static void testLog10Case(double input, double expected) {
48         Tests.test("Math.log10(double)", input,
49                 Math.log10(input), expected);
50 
51         Tests.test("StrictMath.log10(double)", input,
52                 StrictMath.log10(input), expected);
53     }
54 
55     @Test
testLog10()56     public void testLog10() {
57         double[][] testCases = {
58                 {Double.NaN, NaNd},
59                 {Double.longBitsToDouble(0x7FF0000000000001L), NaNd},
60                 {Double.longBitsToDouble(0xFFF0000000000001L), NaNd},
61                 {Double.longBitsToDouble(0x7FF8555555555555L), NaNd},
62                 {Double.longBitsToDouble(0xFFF8555555555555L), NaNd},
63                 {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd},
64                 {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd},
65                 {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd},
66                 {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd},
67                 {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd},
68                 {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd},
69                 {Double.NEGATIVE_INFINITY, NaNd},
70                 {-8.0, NaNd},
71                 {-1.0, NaNd},
72                 {-Double.MIN_NORMAL, NaNd},
73                 {-Double.MIN_VALUE, NaNd},
74                 {-0.0, -infinityD},
75                 {+0.0, -infinityD},
76                 {+1.0, 0.0},
77                 {Double.POSITIVE_INFINITY, infinityD},
78         };
79 
80         // Test special cases
81         for (double[] aCase : testCases) {
82             testLog10Case(aCase[0], aCase[1]);
83         }
84 
85         // Test log10(10^n) == n for integer n; 10^n, n < 0 is not
86         // exactly representable as a floating-point value -- up to
87         // 10^22 can be represented exactly
88         double testCase = 1.0;
89         for (int i = 0; i < 23; i++) {
90             testLog10Case(testCase, i);
91             testCase *= 10.0;
92         }
93 
94         // Test for gross inaccuracy by comparing to log; should be
95         // within a few ulps of log(x)/log(10)
96         for (int i = 0; i < 10000; i++) {
97             double input = Double.longBitsToDouble(rand.nextLong());
98             if (!Double.isFinite(input)) {
99                 continue; // avoid testing NaN and infinite values
100             } else {
101                 input = Math.abs(input);
102 
103                 double expected = StrictMath.log(input) / LN_10;
104                 if (!Double.isFinite(expected)) {
105                     continue; // if log(input) overflowed, try again
106                 } else {
107                     double result;
108 
109                     if (Math.abs(((result = Math.log10(input)) - expected) / Math.ulp(expected))
110                             > 3) {
111                         Assert.fail("For input " + input +
112                                 ", Math.log10 was more than 3 ulps different from " +
113                                 "log(input)/log(10): log10(input) = " + result +
114                                 "\tlog(input)/log(10) = " + expected);
115                     }
116 
117                     if (Math.abs(
118                             ((result = StrictMath.log10(input)) - expected) / Math.ulp(expected))
119                             > 3) {
120                         Assert.fail("For input " + input +
121                                 ", StrictMath.log10 was more than 3 ulps different from " +
122                                 "log(input)/log(10): log10(input) = " + result +
123                                 "\tlog(input)/log(10) = " + expected);
124                     }
125 
126 
127                 }
128             }
129         }
130 
131         // Test for accuracy and monotonicity near log10(1.0).  From
132         // the Taylor expansion of log,
133         // log10(1+z) ~= (z -(z^2)/2)/LN_10;
134         {
135             double[] neighbors = new double[40];
136             double[] neighborsStrict = new double[40];
137             double z = Double.NaN;
138 
139             // Test inputs greater than 1.0.
140             neighbors[0] = Math.log10(1.0);
141             neighborsStrict[0] = StrictMath.log10(1.0);
142 
143             double[] input = new double[40];
144             int half = input.length / 2;
145 
146             // Initialize input to the 40 consecutive double values
147             // "centered" at 1.0.
148             double up = Double.NaN;
149             double down = Double.NaN;
150             for (int i = 0; i < half; i++) {
151                 if (i == 0) {
152                     input[half] = 1.0;
153                     up = Math.nextUp(1.0);
154                     down = Math.nextDown(1.0);
155                 } else {
156                     input[half + i] = up;
157                     input[half - i] = down;
158                     up = Math.nextUp(up);
159                     down = Math.nextDown(down);
160                 }
161             }
162             input[0] = Math.nextDown(input[1]);
163 
164             for (int i = 0; i < neighbors.length; i++) {
165                 neighbors[i] = Math.log10(input[i]);
166                 neighborsStrict[i] = StrictMath.log10(input[i]);
167 
168                 // Test accuracy.
169                 z = input[i] - 1.0;
170                 double expected = (z - (z * z) * 0.5) / LN_10;
171                 if (Math.abs(neighbors[i] - expected) > 3 * Math.ulp(expected)) {
172                     Assert.fail("For input near 1.0 " + input[i] +
173                             ", Math.log10(1+z) was more than 3 ulps different from " +
174                             "(z-(z^2)/2)/ln(10): log10(input) = " + neighbors[i] +
175                             "\texpected about = " + expected);
176                 }
177 
178                 if (Math.abs(neighborsStrict[i] - expected) > 3 * Math.ulp(expected)) {
179                     Assert.fail("For input near 1.0 " + input[i] +
180                             ", StrictMath.log10(1+z) was more than 3 ulps different from " +
181                             "(z-(z^2)/2)/ln(10): log10(input) = " + neighborsStrict[i] +
182                             "\texpected about = " + expected);
183                 }
184 
185                 // Test monotonicity
186                 if (i > 0) {
187                     if (neighbors[i - 1] > neighbors[i]) {
188                         Assert.fail("Monotonicity failure for Math.log10  at " + input[i] +
189                                 " and prior value.");
190                     }
191 
192                     if (neighborsStrict[i - 1] > neighborsStrict[i]) {
193                         Assert.fail("Monotonicity failure for StrictMath.log10  at " + input[i] +
194                                 " and prior value.");
195                     }
196                 }
197             }
198 
199         }
200     }
201 }
202