```   1 /*
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
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  *
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23
24 /*
25  * @test
26  * @bug 4851638 4900189 4939441
27  * @summary Tests for {Math, StrictMath}.expm1
28  * @library /lib/testlibrary
29  * @build jdk.testlibrary.DoubleUtils jdk.testlibrary.FloatUtils
30  * @run main Expm1Tests
31  * @author Joseph D. Darcy
32  */
33
34 import static jdk.testlibrary.DoubleUtils.*;
35
36 /*
37  * The Taylor expansion of expxm1(x) = exp(x) -1 is
38  *
39  * 1 + x/1! + x^2/2! + x^3/3| + ... -1 =
40  *
41  * x + x^2/2! + x^3/3 + ...
42  *
43  * Therefore, for small values of x, expxm1 ~= x.
44  *
45  * For large values of x, expxm1(x) ~= exp(x)
46  *
47  * For large negative x, expxm1(x) ~= -1.
48  */
49
50 public class Expm1Tests {
51
52     private Expm1Tests(){}
53
54     static final double infinityD = Double.POSITIVE_INFINITY;
55     static final double NaNd = Double.NaN;
56
57     static int testExpm1() {
58         int failures = 0;
59
60         double [][] testCases = {
61             {Double.NaN,                NaNd},
62             {Double.longBitsToDouble(0x7FF0000000000001L),      NaNd},
63             {Double.longBitsToDouble(0xFFF0000000000001L),      NaNd},
64             {Double.longBitsToDouble(0x7FF8555555555555L),      NaNd},
65             {Double.longBitsToDouble(0xFFF8555555555555L),      NaNd},
66             {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL),      NaNd},
67             {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL),      NaNd},
70             {Double.longBitsToDouble(0x7FFCafeBabe00000L),      NaNd},
71             {Double.longBitsToDouble(0xFFFCafeBabe00000L),      NaNd},
72             {infinityD,                 infinityD},
73             {-infinityD,                -1.0},
74             {-0.0,                      -0.0},
75             {+0.0,                      +0.0},
76         };
77
78         // Test special cases
79         for(int i = 0; i < testCases.length; i++) {
80             failures += testExpm1CaseWithUlpDiff(testCases[i][0],
81                                                  testCases[i][1], 0, null);
82         }
83
84
85         // For |x| < 2^-54 expm1(x) ~= x
86         for(int i = MIN_SUB_EXPONENT; i <= -54; i++) {
87             double d = Math.scalb(2, i);
88             failures += testExpm1Case(d, d);
89             failures += testExpm1Case(-d, -d);
90         }
91
92
93         // For values of y where exp(y) > 2^54, expm1(x) ~= exp(x).
94         // The least such y is ln(2^54) ~= 37.42994775023705; exp(x)
95         // overflows for x > ~= 709.8
96
97         // Use a 2-ulp error threshold to account for errors in the
98         // exp implementation; the increments of d in the loop will be
99         // exact.
100         for(double d = 37.5; d <= 709.5; d += 1.0) {
101             failures += testExpm1CaseWithUlpDiff(d, StrictMath.exp(d), 2, null);
102         }
103
104         // For x > 710, expm1(x) should be infinity
105         for(int i = 10; i <= Double.MAX_EXPONENT; i++) {
106             double d = Math.scalb(2, i);
107             failures += testExpm1Case(d, infinityD);
108         }
109
110         // By monotonicity, once the limit is reached, the
111         // implemenation should return the limit for all smaller
112         // values.
113         boolean reachedLimit [] = {false, false};
114
115         // Once exp(y) < 0.5 * ulp(1), expm1(y) ~= -1.0;
116         // The greatest such y is ln(2^-53) ~= -36.7368005696771.
117         for(double d = -36.75; d >= -127.75; d -= 1.0) {
118             failures += testExpm1CaseWithUlpDiff(d, -1.0, 1,
119                                                  reachedLimit);
120         }
121
122         for(int i = 7; i <= Double.MAX_EXPONENT; i++) {
123             double d = -Math.scalb(2, i);
124             failures += testExpm1CaseWithUlpDiff(d, -1.0, 1, reachedLimit);
125         }
126
127         // Test for monotonicity failures near multiples of log(2).
128         // Test two numbers before and two numbers after each chosen
129         // value; i.e.
130         //
131         // pcNeighbors[] =
132         // {nextDown(nextDown(pc)),
133         // nextDown(pc),
134         // pc,
135         // nextUp(pc),
136         // nextUp(nextUp(pc))}
137         //
138         // and we test that expm1(pcNeighbors[i]) <= expm1(pcNeighbors[i+1])
139         {
140             double pcNeighbors[] = new double[5];
141             double pcNeighborsExpm1[] = new double[5];
142             double pcNeighborsStrictExpm1[] = new double[5];
143
144             for(int i = -50; i <= 50; i++) {
145                 double pc = StrictMath.log(2)*i;
146
147                 pcNeighbors[2] = pc;
148                 pcNeighbors[1] = Math.nextDown(pc);
149                 pcNeighbors[0] = Math.nextDown(pcNeighbors[1]);
150                 pcNeighbors[3] = Math.nextUp(pc);
151                 pcNeighbors[4] = Math.nextUp(pcNeighbors[3]);
152
153                 for(int j = 0; j < pcNeighbors.length; j++) {
154                     pcNeighborsExpm1[j]       =       Math.expm1(pcNeighbors[j]);
156                 }
157
158                 for(int j = 0; j < pcNeighborsExpm1.length-1; j++) {
159                     if(pcNeighborsExpm1[j] >  pcNeighborsExpm1[j+1] ) {
160                         failures++;
161                         System.err.println("Monotonicity failure for Math.expm1 on " +
162                                           pcNeighbors[j] + " and "  +
163                                           pcNeighbors[j+1] + "\n\treturned " +
164                                           pcNeighborsExpm1[j] + " and " +
165                                           pcNeighborsExpm1[j+1] );
166                     }
167
169                         failures++;
170                         System.err.println("Monotonicity failure for StrictMath.expm1 on " +
171                                           pcNeighbors[j] + " and "  +
172                                           pcNeighbors[j+1] + "\n\treturned " +
173                                           pcNeighborsStrictExpm1[j] + " and " +
175                     }
176
177
178                 }
179
180             }
181         }
182
183         return failures;
184     }
185
186     public static int testExpm1Case(double input,
187                                     double expected) {
188         return testExpm1CaseWithUlpDiff(input, expected, 1, null);
189     }
190
191     public static int testExpm1CaseWithUlpDiff(double input,
192                                                double expected,
193                                                double ulps,
194                                                boolean [] reachedLimit) {
195         int failures = 0;
196         double mathUlps = ulps, strictUlps = ulps;
197         double mathOutput;
198         double strictOutput;
199
200         if (reachedLimit != null) {
201             if (reachedLimit[0])
202                 mathUlps = 0;
203
204             if (reachedLimit[1])
205                 strictUlps = 0;
206         }
207
208         failures += Tests.testUlpDiffWithLowerBound("Math.expm1(double)",
209                                                     input, mathOutput=Math.expm1(input),
210                                                     expected, mathUlps, -1.0);
211         failures += Tests.testUlpDiffWithLowerBound("StrictMath.expm1(double)",
212                                                     input, strictOutput=StrictMath.expm1(input),
213                                                     expected, strictUlps, -1.0);
214         if (reachedLimit != null) {
215             reachedLimit[0] |= (mathOutput   == -1.0);
216             reachedLimit[1] |= (strictOutput == -1.0);
217         }
218
219         return failures;
220     }
221
222     public static void main(String argv[]) {
223         int failures = 0;
224
225         failures += testExpm1();
226
227         if (failures > 0) {
228             System.err.println("Testing expm1 incurred "
229                                + failures + " failures.");
230             throw new RuntimeException();
231         }
232     }
233 }
```