blob: 6b70da3e43f6440c0a7438e41c87a8ce7ebedbfa [file] [log] [blame]
darcy32db4492009-01-26 19:49:26 -08001/*
ohair2283b9d2010-05-25 15:58:33 -07002 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
darcy32db4492009-01-26 19:49:26 -08003 * 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 *
ohair2283b9d2010-05-25 15:58:33 -070019 * 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.
darcy32db4492009-01-26 19:49:26 -080022 */
23
24/*
25 * @test
26 * @bug 4347132 4939441
27 * @summary Tests for {Math, StrictMath}.cbrt
28 * @author Joseph D. Darcy
29 */
30
31import sun.misc.FpUtils;
32import sun.misc.DoubleConsts;
33
34public class CubeRootTests {
35 private CubeRootTests(){}
36
37 static final double infinityD = Double.POSITIVE_INFINITY;
38 static final double NaNd = Double.NaN;
39
40 // Initialize shared random number generator
41 static java.util.Random rand = new java.util.Random();
42
43 static int testCubeRootCase(double input, double expected) {
44 int failures=0;
45
46 double minus_input = -input;
47 double minus_expected = -expected;
48
49 failures+=Tests.test("Math.cbrt(double)", input,
50 Math.cbrt(input), expected);
51 failures+=Tests.test("Math.cbrt(double)", minus_input,
52 Math.cbrt(minus_input), minus_expected);
53 failures+=Tests.test("StrictMath.cbrt(double)", input,
54 StrictMath.cbrt(input), expected);
55 failures+=Tests.test("StrictMath.cbrt(double)", minus_input,
56 StrictMath.cbrt(minus_input), minus_expected);
57
58 return failures;
59 }
60
61 static int testCubeRoot() {
62 int failures = 0;
63 double [][] testCases = {
64 {NaNd, NaNd},
65 {Double.longBitsToDouble(0x7FF0000000000001L), NaNd},
66 {Double.longBitsToDouble(0xFFF0000000000001L), NaNd},
67 {Double.longBitsToDouble(0x7FF8555555555555L), NaNd},
68 {Double.longBitsToDouble(0xFFF8555555555555L), NaNd},
69 {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd},
70 {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd},
71 {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd},
72 {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd},
73 {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd},
74 {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd},
75 {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
76 {Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY},
77 {+0.0, +0.0},
78 {-0.0, -0.0},
79 {+1.0, +1.0},
80 {-1.0, -1.0},
81 {+8.0, +2.0},
82 {-8.0, -2.0}
83 };
84
85 for(int i = 0; i < testCases.length; i++) {
86 failures += testCubeRootCase(testCases[i][0],
87 testCases[i][1]);
88 }
89
90 // Test integer perfect cubes less than 2^53.
91 for(int i = 0; i <= 208063; i++) {
92 double d = i;
93 failures += testCubeRootCase(d*d*d, (double)i);
94 }
95
96 // Test cbrt(2^(3n)) = 2^n.
97 for(int i = 18; i <= DoubleConsts.MAX_EXPONENT/3; i++) {
98 failures += testCubeRootCase(FpUtils.scalb(1.0, 3*i),
99 FpUtils.scalb(1.0, i) );
100 }
101
102 // Test cbrt(2^(-3n)) = 2^-n.
103 for(int i = -1; i >= FpUtils.ilogb(Double.MIN_VALUE)/3; i--) {
104 failures += testCubeRootCase(FpUtils.scalb(1.0, 3*i),
105 FpUtils.scalb(1.0, i) );
106 }
107
108 // Test random perfect cubes. Create double values with
109 // modest exponents but only have at most the 17 most
110 // significant bits in the significand set; 17*3 = 51, which
111 // is less than the number of bits in a double's significand.
112 long exponentBits1 =
113 Double.doubleToLongBits(FpUtils.scalb(1.0, 55)) &
114 DoubleConsts.EXP_BIT_MASK;
115 long exponentBits2=
116 Double.doubleToLongBits(FpUtils.scalb(1.0, -55)) &
117 DoubleConsts.EXP_BIT_MASK;
118 for(int i = 0; i < 100; i++) {
119 // Take 16 bits since the 17th bit is implicit in the
120 // exponent
121 double input1 =
122 Double.longBitsToDouble(exponentBits1 |
123 // Significand bits
124 ((long) (rand.nextInt() & 0xFFFF))<<
125 (DoubleConsts.SIGNIFICAND_WIDTH-1-16));
126 failures += testCubeRootCase(input1*input1*input1, input1);
127
128 double input2 =
129 Double.longBitsToDouble(exponentBits2 |
130 // Significand bits
131 ((long) (rand.nextInt() & 0xFFFF))<<
132 (DoubleConsts.SIGNIFICAND_WIDTH-1-16));
133 failures += testCubeRootCase(input2*input2*input2, input2);
134 }
135
136 // Directly test quality of implementation properties of cbrt
137 // for values that aren't perfect cubes. Verify returned
138 // result meets the 1 ulp test. That is, we want to verify
139 // that for positive x > 1,
140 // y = cbrt(x),
141 //
142 // if (err1=x - y^3 ) < 0, abs((y_pp^3 -x )) < err1
143 // if (err1=x - y^3 ) > 0, abs((y_mm^3 -x )) < err1
144 //
145 // where y_mm and y_pp are the next smaller and next larger
146 // floating-point value to y. In other words, if y^3 is too
147 // big, making y larger does not improve the result; likewise,
148 // if y^3 is too small, making y smaller does not improve the
149 // result.
150 //
151 // ...-----|--?--|--?--|-----... Where is the true result?
152 // y_mm y y_pp
153 //
154 // The returned value y should be one of the floating-point
155 // values braketing the true result. However, given y, a
156 // priori we don't know if the true result falls in [y_mm, y]
157 // or [y, y_pp]. The above test looks at the error in x-y^3
158 // to determine which region the true result is in; e.g. if
159 // y^3 is smaller than x, the true result should be in [y,
160 // y_pp]. Therefore, it would be an error for y_mm to be a
161 // closer approximation to x^(1/3). In this case, it is
162 // permissible, although not ideal, for y_pp^3 to be a closer
163 // approximation to x^(1/3) than y^3.
164 //
165 // We will use pow(y,3) to compute y^3. Although pow is not
166 // correctly rounded, StrictMath.pow should have at most 1 ulp
167 // error. For y > 1, pow(y_mm,3) and pow(y_pp,3) will differ
168 // from pow(y,3) by more than one ulp so the comparision of
169 // errors should still be valid.
170
171 for(int i = 0; i < 1000; i++) {
172 double d = 1.0 + rand.nextDouble();
173 double err, err_adjacent;
174
175 double y1 = Math.cbrt(d);
176 double y2 = StrictMath.cbrt(d);
177
178 err = d - StrictMath.pow(y1, 3);
179 if (err != 0.0) {
180 if(FpUtils.isNaN(err)) {
181 failures++;
182 System.err.println("Encountered unexpected NaN value: d = " + d +
183 "\tcbrt(d) = " + y1);
184 } else {
185 if (err < 0.0) {
186 err_adjacent = StrictMath.pow(FpUtils.nextUp(y1), 3) - d;
187 }
188 else { // (err > 0.0)
189 err_adjacent = StrictMath.pow(FpUtils.nextAfter(y1,0.0), 3) - d;
190 }
191
192 if (Math.abs(err) > Math.abs(err_adjacent)) {
193 failures++;
194 System.err.println("For Math.cbrt(" + d + "), returned result " +
195 y1 + "is not as good as adjacent value.");
196 }
197 }
198 }
199
200
201 err = d - StrictMath.pow(y2, 3);
202 if (err != 0.0) {
203 if(FpUtils.isNaN(err)) {
204 failures++;
205 System.err.println("Encountered unexpected NaN value: d = " + d +
206 "\tcbrt(d) = " + y2);
207 } else {
208 if (err < 0.0) {
209 err_adjacent = StrictMath.pow(FpUtils.nextUp(y2), 3) - d;
210 }
211 else { // (err > 0.0)
212 err_adjacent = StrictMath.pow(FpUtils.nextAfter(y2,0.0), 3) - d;
213 }
214
215 if (Math.abs(err) > Math.abs(err_adjacent)) {
216 failures++;
217 System.err.println("For StrictMath.cbrt(" + d + "), returned result " +
218 y2 + "is not as good as adjacent value.");
219 }
220 }
221 }
222
223
224 }
225
226 // Test monotonicity properites near perfect cubes; test two
227 // numbers before and two numbers after; i.e. for
228 //
229 // pcNeighbors[] =
230 // {nextDown(nextDown(pc)),
231 // nextDown(pc),
232 // pc,
233 // nextUp(pc),
234 // nextUp(nextUp(pc))}
235 //
236 // test that cbrt(pcNeighbors[i]) <= cbrt(pcNeighbors[i+1])
237 {
238
239 double pcNeighbors[] = new double[5];
240 double pcNeighborsCbrt[] = new double[5];
241 double pcNeighborsStrictCbrt[] = new double[5];
242
243 // Test near cbrt(2^(3n)) = 2^n.
244 for(int i = 18; i <= DoubleConsts.MAX_EXPONENT/3; i++) {
245 double pc = FpUtils.scalb(1.0, 3*i);
246
247 pcNeighbors[2] = pc;
248 pcNeighbors[1] = FpUtils.nextDown(pc);
249 pcNeighbors[0] = FpUtils.nextDown(pcNeighbors[1]);
250 pcNeighbors[3] = FpUtils.nextUp(pc);
251 pcNeighbors[4] = FpUtils.nextUp(pcNeighbors[3]);
252
253 for(int j = 0; j < pcNeighbors.length; j++) {
254 pcNeighborsCbrt[j] = Math.cbrt(pcNeighbors[j]);
255 pcNeighborsStrictCbrt[j] = StrictMath.cbrt(pcNeighbors[j]);
256 }
257
258 for(int j = 0; j < pcNeighborsCbrt.length-1; j++) {
259 if(pcNeighborsCbrt[j] > pcNeighborsCbrt[j+1] ) {
260 failures++;
261 System.err.println("Monotonicity failure for Math.cbrt on " +
262 pcNeighbors[j] + " and " +
263 pcNeighbors[j+1] + "\n\treturned " +
264 pcNeighborsCbrt[j] + " and " +
265 pcNeighborsCbrt[j+1] );
266 }
267
268 if(pcNeighborsStrictCbrt[j] > pcNeighborsStrictCbrt[j+1] ) {
269 failures++;
270 System.err.println("Monotonicity failure for StrictMath.cbrt on " +
271 pcNeighbors[j] + " and " +
272 pcNeighbors[j+1] + "\n\treturned " +
273 pcNeighborsStrictCbrt[j] + " and " +
274 pcNeighborsStrictCbrt[j+1] );
275 }
276
277
278 }
279
280 }
281
282 // Test near cbrt(2^(-3n)) = 2^-n.
283 for(int i = -1; i >= FpUtils.ilogb(Double.MIN_VALUE)/3; i--) {
284 double pc = FpUtils.scalb(1.0, 3*i);
285
286 pcNeighbors[2] = pc;
287 pcNeighbors[1] = FpUtils.nextDown(pc);
288 pcNeighbors[0] = FpUtils.nextDown(pcNeighbors[1]);
289 pcNeighbors[3] = FpUtils.nextUp(pc);
290 pcNeighbors[4] = FpUtils.nextUp(pcNeighbors[3]);
291
292 for(int j = 0; j < pcNeighbors.length; j++) {
293 pcNeighborsCbrt[j] = Math.cbrt(pcNeighbors[j]);
294 pcNeighborsStrictCbrt[j] = StrictMath.cbrt(pcNeighbors[j]);
295 }
296
297 for(int j = 0; j < pcNeighborsCbrt.length-1; j++) {
298 if(pcNeighborsCbrt[j] > pcNeighborsCbrt[j+1] ) {
299 failures++;
300 System.err.println("Monotonicity failure for Math.cbrt on " +
301 pcNeighbors[j] + " and " +
302 pcNeighbors[j+1] + "\n\treturned " +
303 pcNeighborsCbrt[j] + " and " +
304 pcNeighborsCbrt[j+1] );
305 }
306
307 if(pcNeighborsStrictCbrt[j] > pcNeighborsStrictCbrt[j+1] ) {
308 failures++;
309 System.err.println("Monotonicity failure for StrictMath.cbrt on " +
310 pcNeighbors[j] + " and " +
311 pcNeighbors[j+1] + "\n\treturned " +
312 pcNeighborsStrictCbrt[j] + " and " +
313 pcNeighborsStrictCbrt[j+1] );
314 }
315
316
317 }
318 }
319 }
320
321 return failures;
322 }
323
324 public static void main(String argv[]) {
325 int failures = 0;
326
327 failures += testCubeRoot();
328
329 if (failures > 0) {
330 System.err.println("Testing cbrt incurred "
331 + failures + " failures.");
332 throw new RuntimeException();
333 }
334 }
335
336}