1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.legacy.core.jdkmath;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assert.fail;
22
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25 import java.math.RoundingMode;
26
27 import org.junit.Assert;
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.junit.jupiter.api.Assertions;
31 import org.apache.commons.numbers.core.ArithmeticUtils;
32 import org.apache.commons.numbers.core.Precision;
33 import org.apache.commons.math4.legacy.core.dfp.Dfp;
34 import org.apache.commons.math4.legacy.core.dfp.DfpField;
35 import org.apache.commons.math4.legacy.core.dfp.DfpMath;
36 import org.apache.commons.rng.UniformRandomProvider;
37 import org.apache.commons.rng.simple.RandomSource;
38
39
40
41 import org.apache.commons.math4.core.jdkmath.AccurateMath;
42
43 public class AccurateMathTest {
44
45
46
47 private static final double MAX_ERROR_ULP = 0.51;
48 private static final int NUMBER_OF_TRIALS = 1000;
49
50 private DfpField field;
51 private UniformRandomProvider generator;
52
53 @Before
54 public void setUp() {
55 field = new DfpField(40);
56 generator = RandomSource.MT.create(6176597458463500194L);
57 }
58
59 @Test
60 public void testMinMaxDouble() {
61 double[][] pairs = {
62 {-50.0, 50.0},
63 {Double.POSITIVE_INFINITY, 1.0},
64 {Double.NEGATIVE_INFINITY, 1.0},
65 {Double.NaN, 1.0},
66 {Double.POSITIVE_INFINITY, 0.0},
67 {Double.NEGATIVE_INFINITY, 0.0},
68 {Double.NaN, 0.0},
69 {Double.NaN, Double.NEGATIVE_INFINITY},
70 {Double.NaN, Double.POSITIVE_INFINITY},
71 {Precision.SAFE_MIN, Precision.EPSILON}
72 };
73 for (double[] pair : pairs) {
74 assertEquals("min(" + pair[0] + ", " + pair[1] + ")",
75 Math.min(pair[0], pair[1]),
76 AccurateMath.min(pair[0], pair[1]),
77 Precision.EPSILON);
78 assertEquals("min(" + pair[1] + ", " + pair[0] + ")",
79 Math.min(pair[1], pair[0]),
80 AccurateMath.min(pair[1], pair[0]),
81 Precision.EPSILON);
82 assertEquals("max(" + pair[0] + ", " + pair[1] + ")",
83 Math.max(pair[0], pair[1]),
84 AccurateMath.max(pair[0], pair[1]),
85 Precision.EPSILON);
86 assertEquals("max(" + pair[1] + ", " + pair[0] + ")",
87 Math.max(pair[1], pair[0]),
88 AccurateMath.max(pair[1], pair[0]),
89 Precision.EPSILON);
90 }
91 }
92
93 @Test
94 public void testMinMaxFloat() {
95 float[][] pairs = {
96 {-50.0f, 50.0f},
97 {Float.POSITIVE_INFINITY, 1.0f},
98 {Float.NEGATIVE_INFINITY, 1.0f},
99 {Float.NaN, 1.0f},
100 {Float.POSITIVE_INFINITY, 0.0f},
101 {Float.NEGATIVE_INFINITY, 0.0f},
102 {Float.NaN, 0.0f},
103 {Float.NaN, Float.NEGATIVE_INFINITY},
104 {Float.NaN, Float.POSITIVE_INFINITY}
105 };
106 for (float[] pair : pairs) {
107 assertEquals("min(" + pair[0] + ", " + pair[1] + ")",
108 Math.min(pair[0], pair[1]),
109 AccurateMath.min(pair[0], pair[1]),
110 Precision.EPSILON);
111 assertEquals("min(" + pair[1] + ", " + pair[0] + ")",
112 Math.min(pair[1], pair[0]),
113 AccurateMath.min(pair[1], pair[0]),
114 Precision.EPSILON);
115 assertEquals("max(" + pair[0] + ", " + pair[1] + ")",
116 Math.max(pair[0], pair[1]),
117 AccurateMath.max(pair[0], pair[1]),
118 Precision.EPSILON);
119 assertEquals("max(" + pair[1] + ", " + pair[0] + ")",
120 Math.max(pair[1], pair[0]),
121 AccurateMath.max(pair[1], pair[0]),
122 Precision.EPSILON);
123 }
124 }
125
126 @Test
127 public void testConstants() {
128 assertEquals(Math.PI, AccurateMath.PI, 1.0e-20);
129 assertEquals(Math.E, AccurateMath.E, 1.0e-20);
130 }
131
132 @Test
133 public void testAtan2() {
134 double y1 = 1.2713504628280707e10;
135 double x1 = -5.674940885228782e-10;
136 assertEquals(Math.atan2(y1, x1), AccurateMath.atan2(y1, x1), 2 * Precision.EPSILON);
137 double y2 = 0.0;
138 double x2 = Double.POSITIVE_INFINITY;
139 assertEquals(Math.atan2(y2, x2), AccurateMath.atan2(y2, x2), Precision.SAFE_MIN);
140 }
141
142 @Test
143 public void testHyperbolic() {
144 double maxErr = 0;
145 for (double x = -30; x < 30; x += 0.001) {
146 double tst = AccurateMath.sinh(x);
147 double ref = Math.sinh(x);
148 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(ref - tst) / AccurateMath.ulp(ref));
149 }
150 assertEquals(0, maxErr, 2);
151
152 maxErr = 0;
153 for (double x = -30; x < 30; x += 0.001) {
154 double tst = AccurateMath.cosh(x);
155 double ref = Math.cosh(x);
156 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(ref - tst) / AccurateMath.ulp(ref));
157 }
158 assertEquals(0, maxErr, 2);
159
160 maxErr = 0;
161 for (double x = -0.5; x < 0.5; x += 0.001) {
162 double tst = AccurateMath.tanh(x);
163 double ref = Math.tanh(x);
164 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(ref - tst) / AccurateMath.ulp(ref));
165 }
166 assertEquals(0, maxErr, 4);
167 }
168
169 @Test
170 public void testMath904() {
171 final double x = -1;
172 final double y = (5 + 1e-15) * 1e15;
173 assertEquals(Math.pow(x, y),
174 AccurateMath.pow(x, y), 0);
175 assertEquals(Math.pow(x, -y),
176 AccurateMath.pow(x, -y), 0);
177 }
178
179 @Test
180 public void testMath905LargePositive() {
181 final double start = StrictMath.log(Double.MAX_VALUE);
182 final double endT = StrictMath.sqrt(2) * StrictMath.sqrt(Double.MAX_VALUE);
183 final double end = 2 * StrictMath.log(endT);
184
185 double maxErr = 0;
186 for (double x = start; x < end; x += 1e-3) {
187 final double tst = AccurateMath.cosh(x);
188 final double ref = Math.cosh(x);
189 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(ref - tst) / AccurateMath.ulp(ref));
190 }
191 assertEquals(0, maxErr, 3);
192
193 for (double x = start; x < end; x += 1e-3) {
194 final double tst = AccurateMath.sinh(x);
195 final double ref = Math.sinh(x);
196 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(ref - tst) / AccurateMath.ulp(ref));
197 }
198 assertEquals(0, maxErr, 3);
199 }
200
201 @Test
202 public void testMath905LargeNegative() {
203 final double start = -StrictMath.log(Double.MAX_VALUE);
204 final double endT = StrictMath.sqrt(2) * StrictMath.sqrt(Double.MAX_VALUE);
205 final double end = -2 * StrictMath.log(endT);
206
207 double maxErr = 0;
208 for (double x = start; x > end; x -= 1e-3) {
209 final double tst = AccurateMath.cosh(x);
210 final double ref = Math.cosh(x);
211 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(ref - tst) / AccurateMath.ulp(ref));
212 }
213 assertEquals(0, maxErr, 3);
214
215 for (double x = start; x > end; x -= 1e-3) {
216 final double tst = AccurateMath.sinh(x);
217 final double ref = Math.sinh(x);
218 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(ref - tst) / AccurateMath.ulp(ref));
219 }
220 assertEquals(0, maxErr, 3);
221 }
222
223 @Test
224 public void testMath1269() {
225 final double arg = 709.8125;
226 final double vM = Math.exp(arg);
227 final double vFM = AccurateMath.exp(arg);
228 assertTrue("exp(" + arg + ") is " + vFM + " instead of " + vM,
229 Precision.equalsIncludingNaN(vM, vFM));
230 }
231
232 @Test
233 public void testHyperbolicInverses() {
234 double maxErr = 0;
235 for (double x = -30; x < 30; x += 0.01) {
236 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(x - AccurateMath.sinh(AccurateMath.asinh(x))) / (2 * AccurateMath.ulp(x)));
237 }
238 assertEquals(0, maxErr, 3);
239
240 maxErr = 0;
241 for (double x = 1; x < 30; x += 0.01) {
242 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(x - AccurateMath.cosh(AccurateMath.acosh(x))) / (2 * AccurateMath.ulp(x)));
243 }
244 assertEquals(0, maxErr, 2);
245
246 maxErr = 0;
247 for (double x = -1 + Precision.EPSILON; x < 1 - Precision.EPSILON; x += 0.0001) {
248 maxErr = AccurateMath.max(maxErr, AccurateMath.abs(x - AccurateMath.tanh(AccurateMath.atanh(x))) / (2 * AccurateMath.ulp(x)));
249 }
250 assertEquals(0, maxErr, 2);
251 }
252
253 @Test
254 public void testLogAccuracy() {
255 double maxerrulp = 0.0;
256
257 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
258 double x = Math.exp(generator.nextDouble() * 1416.0 - 708.0) * generator.nextDouble();
259
260 double tst = AccurateMath.log(x);
261 double ref = DfpMath.log(field.newDfp(x)).toDouble();
262 double err = (tst - ref) / ref;
263
264 if (err != 0.0) {
265 double ulp = Math.abs(ref -
266 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
267 double errulp = field.newDfp(tst).subtract(DfpMath.log(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
268
269
270 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
271 }
272 }
273
274 assertTrue("log() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
275 }
276
277 @Test
278 public void testLog10Accuracy() {
279 double maxerrulp = 0.0;
280
281 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
282 double x = Math.exp(generator.nextDouble() * 1416.0 - 708.0) * generator.nextDouble();
283
284 double tst = AccurateMath.log10(x);
285 double ref = DfpMath.log(field.newDfp(x)).divide(DfpMath.log(field.newDfp("10"))).toDouble();
286 double err = (tst - ref) / ref;
287
288 if (err != 0.0) {
289 double ulp = Math.abs(ref -
290 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
291 double errulp = field.newDfp(tst).subtract(DfpMath.log(field.newDfp(x)).divide(DfpMath.log(field.newDfp("10")))).divide(field.newDfp(ulp)).toDouble();
292
293
294 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
295 }
296 }
297
298 assertTrue("log10() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
299 }
300
301 @Test
302 public void testLog1pAccuracy() {
303 double maxerrulp = 0.0;
304
305 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
306 double x = Math.exp(generator.nextDouble() * 10.0 - 5.0) * generator.nextDouble();
307
308 double tst = AccurateMath.log1p(x);
309 double ref = DfpMath.log(field.newDfp(x).add(field.getOne())).toDouble();
310 double err = (tst - ref) / ref;
311
312 if (err != 0.0) {
313 double ulp = Math.abs(ref -
314 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
315 double errulp = field.newDfp(tst).subtract(DfpMath.log(field.newDfp(x).add(field.getOne()))).divide(field.newDfp(ulp)).toDouble();
316
317
318 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
319 }
320 }
321
322 assertTrue("log1p() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
323 }
324
325 @Test
326 public void testLog1pSpecialCases() {
327 assertTrue("Logp of -1.0 should be -Inf", Double.isInfinite(AccurateMath.log1p(-1.0)));
328 }
329
330 @Test
331 public void testLogSpecialCases() {
332 assertEquals("Log of zero should be -Inf", Double.NEGATIVE_INFINITY, AccurateMath.log(0.0), 1.0);
333 assertEquals("Log of -zero should be -Inf", Double.NEGATIVE_INFINITY, AccurateMath.log(-0.0), 1.0);
334 assertTrue("Log of NaN should be NaN", Double.isNaN(AccurateMath.log(Double.NaN)));
335 assertTrue("Log of negative number should be NaN", Double.isNaN(AccurateMath.log(-1.0)));
336 assertEquals("Log of Double.MIN_VALUE should be -744.4400719213812", -744.4400719213812, AccurateMath.log(Double.MIN_VALUE), Precision.EPSILON);
337 assertEquals("Log of infinity should be infinity", Double.POSITIVE_INFINITY, AccurateMath.log(Double.POSITIVE_INFINITY), 1.0);
338 }
339
340 @Test
341 public void testExpSpecialCases() {
342
343 assertEquals(Double.MIN_VALUE, AccurateMath.exp(-745.1332191019411), Precision.EPSILON);
344 assertEquals("exp(-745.1332191019412) should be 0.0", 0.0, AccurateMath.exp(-745.1332191019412), Precision.EPSILON);
345 assertTrue("exp of NaN should be NaN", Double.isNaN(AccurateMath.exp(Double.NaN)));
346 assertEquals("exp of infinity should be infinity", Double.POSITIVE_INFINITY, AccurateMath.exp(Double.POSITIVE_INFINITY), 1.0);
347 assertEquals("exp of -infinity should be 0.0", 0.0, AccurateMath.exp(Double.NEGATIVE_INFINITY), Precision.EPSILON);
348 assertEquals("exp(1) should be Math.E", Math.E, AccurateMath.exp(1.0), Precision.EPSILON);
349 }
350
351 @Test
352 public void testPowSpecialCases() {
353 final double EXACT = -1.0;
354
355 assertEquals("pow(-1, 0) should be 1.0", 1.0, AccurateMath.pow(-1.0, 0.0), Precision.EPSILON);
356 assertEquals("pow(-1, -0) should be 1.0", 1.0, AccurateMath.pow(-1.0, -0.0), Precision.EPSILON);
357 assertEquals("pow(PI, 1.0) should be PI", AccurateMath.PI, AccurateMath.pow(AccurateMath.PI, 1.0), Precision.EPSILON);
358 assertEquals("pow(-PI, 1.0) should be -PI", -AccurateMath.PI, AccurateMath.pow(-AccurateMath.PI, 1.0), Precision.EPSILON);
359 assertTrue("pow(PI, NaN) should be NaN", Double.isNaN(AccurateMath.pow(Math.PI, Double.NaN)));
360 assertTrue("pow(NaN, PI) should be NaN", Double.isNaN(AccurateMath.pow(Double.NaN, Math.PI)));
361 assertEquals("pow(2.0, Infinity) should be Infinity", Double.POSITIVE_INFINITY, AccurateMath.pow(2.0, Double.POSITIVE_INFINITY), 1.0);
362 assertEquals("pow(0.5, -Infinity) should be Infinity", Double.POSITIVE_INFINITY, AccurateMath.pow(0.5, Double.NEGATIVE_INFINITY), 1.0);
363 assertEquals("pow(0.5, Infinity) should be 0.0", 0.0, AccurateMath.pow(0.5, Double.POSITIVE_INFINITY), Precision.EPSILON);
364 assertEquals("pow(2.0, -Infinity) should be 0.0", 0.0, AccurateMath.pow(2.0, Double.NEGATIVE_INFINITY), Precision.EPSILON);
365 assertEquals("pow(0.0, 0.5) should be 0.0", 0.0, AccurateMath.pow(0.0, 0.5), Precision.EPSILON);
366 assertEquals("pow(Infinity, -0.5) should be 0.0", 0.0, AccurateMath.pow(Double.POSITIVE_INFINITY, -0.5), Precision.EPSILON);
367 assertEquals("pow(0.0, -0.5) should be Inf", Double.POSITIVE_INFINITY, AccurateMath.pow(0.0, -0.5), 1.0);
368 assertEquals("pow(Inf, 0.5) should be Inf", Double.POSITIVE_INFINITY, AccurateMath.pow(Double.POSITIVE_INFINITY, 0.5), 1.0);
369 assertEquals("pow(-0.0, -3.0) should be -Inf", Double.NEGATIVE_INFINITY, AccurateMath.pow(-0.0, -3.0), 1.0);
370 assertEquals("pow(-0.0, Infinity) should be 0.0", 0.0, AccurateMath.pow(-0.0, Double.POSITIVE_INFINITY), Precision.EPSILON);
371 assertTrue("pow(-0.0, NaN) should be NaN", Double.isNaN(AccurateMath.pow(-0.0, Double.NaN)));
372 assertEquals("pow(-0.0, -tiny) should be Infinity", Double.POSITIVE_INFINITY, AccurateMath.pow(-0.0, -Double.MIN_VALUE), 1.0);
373 assertEquals("pow(-0.0, -huge) should be Infinity", Double.POSITIVE_INFINITY, AccurateMath.pow(-0.0, -Double.MAX_VALUE), 1.0);
374 assertEquals("pow(-Inf, 3.0) should be -Inf", Double.NEGATIVE_INFINITY, AccurateMath.pow(Double.NEGATIVE_INFINITY, 3.0), 1.0);
375 assertEquals("pow(-Inf, -3.0) should be -0.0", -0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, -3.0), EXACT);
376 assertEquals("pow(-0.0, -3.5) should be Inf", Double.POSITIVE_INFINITY, AccurateMath.pow(-0.0, -3.5), 1.0);
377 assertEquals("pow(Inf, 3.5) should be Inf", Double.POSITIVE_INFINITY, AccurateMath.pow(Double.POSITIVE_INFINITY, 3.5), 1.0);
378 assertEquals("pow(-2.0, 3.0) should be -8.0", -8.0, AccurateMath.pow(-2.0, 3.0), Precision.EPSILON);
379 assertTrue("pow(-2.0, 3.5) should be NaN", Double.isNaN(AccurateMath.pow(-2.0, 3.5)));
380 assertTrue("pow(NaN, -Infinity) should be NaN", Double.isNaN(AccurateMath.pow(Double.NaN, Double.NEGATIVE_INFINITY)));
381 assertEquals("pow(NaN, 0.0) should be 1.0", 1.0, AccurateMath.pow(Double.NaN, 0.0), Precision.EPSILON);
382 assertEquals("pow(-Infinity, -Infinity) should be 0.0", 0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY), Precision.EPSILON);
383 assertEquals("pow(-huge, -huge) should be 0.0", 0.0, AccurateMath.pow(-Double.MAX_VALUE, -Double.MAX_VALUE), Precision.EPSILON);
384 assertTrue("pow(-huge, huge) should be +Inf", Double.isInfinite(AccurateMath.pow(-Double.MAX_VALUE, Double.MAX_VALUE)));
385 assertTrue("pow(NaN, -Infinity) should be NaN", Double.isNaN(AccurateMath.pow(Double.NaN, Double.NEGATIVE_INFINITY)));
386 assertEquals("pow(NaN, -0.0) should be 1.0", 1.0, AccurateMath.pow(Double.NaN, -0.0), Precision.EPSILON);
387 assertEquals("pow(-Infinity, -Infinity) should be 0.0", 0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY), Precision.EPSILON);
388 assertEquals("pow(-huge, -huge) should be 0.0", 0.0, AccurateMath.pow(-Double.MAX_VALUE, -Double.MAX_VALUE), Precision.EPSILON);
389 assertEquals("pow(-huge, huge) should be +Inf", Double.POSITIVE_INFINITY, AccurateMath.pow(-Double.MAX_VALUE, Double.MAX_VALUE), 1.0);
390
391
392
393 assertTrue("pow(+Inf, NaN) should be NaN", Double.isNaN(AccurateMath.pow(Double.POSITIVE_INFINITY, Double.NaN)));
394 assertTrue("pow(1.0, +Inf) should be NaN", Double.isNaN(AccurateMath.pow(1.0, Double.POSITIVE_INFINITY)));
395 assertTrue("pow(-Inf, NaN) should be NaN", Double.isNaN(AccurateMath.pow(Double.NEGATIVE_INFINITY, Double.NaN)));
396 assertEquals("pow(-Inf, -1.0) should be -0.0", -0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, -1.0), EXACT);
397 assertEquals("pow(-Inf, -2.0) should be 0.0", 0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, -2.0), EXACT);
398 assertEquals("pow(-Inf, 1.0) should be -Inf", Double.NEGATIVE_INFINITY, AccurateMath.pow(Double.NEGATIVE_INFINITY, 1.0), 1.0);
399 assertEquals("pow(-Inf, 2.0) should be +Inf", Double.POSITIVE_INFINITY, AccurateMath.pow(Double.NEGATIVE_INFINITY, 2.0), 1.0);
400 assertTrue("pow(1.0, -Inf) should be NaN", Double.isNaN(AccurateMath.pow(1.0, Double.NEGATIVE_INFINITY)));
401 assertEquals("pow(-0.0, 1.0) should be -0.0", -0.0, AccurateMath.pow(-0.0, 1.0), EXACT);
402 assertEquals("pow(0.0, 1.0) should be 0.0", 0.0, AccurateMath.pow(0.0, 1.0), EXACT);
403 assertEquals("pow(0.0, +Inf) should be 0.0", 0.0, AccurateMath.pow(0.0, Double.POSITIVE_INFINITY), EXACT);
404 assertEquals("pow(-0.0, even) should be 0.0", 0.0, AccurateMath.pow(-0.0, 6.0), EXACT);
405 assertEquals("pow(-0.0, odd) should be -0.0", -0.0, AccurateMath.pow(-0.0, 13.0), EXACT);
406 assertEquals("pow(-0.0, -even) should be +Inf", Double.POSITIVE_INFINITY, AccurateMath.pow(-0.0, -6.0), EXACT);
407 assertEquals("pow(-0.0, -odd) should be -Inf", Double.NEGATIVE_INFINITY, AccurateMath.pow(-0.0, -13.0), EXACT);
408 assertEquals("pow(-2.0, 4.0) should be 16.0", 16.0, AccurateMath.pow(-2.0, 4.0), EXACT);
409 assertEquals("pow(-2.0, 4.5) should be NaN", Double.NaN, AccurateMath.pow(-2.0, 4.5), EXACT);
410 assertEquals("pow(-0.0, -0.0) should be 1.0", 1.0, AccurateMath.pow(-0.0, -0.0), EXACT);
411 assertEquals("pow(-0.0, 0.0) should be 1.0", 1.0, AccurateMath.pow(-0.0, 0.0), EXACT);
412 assertEquals("pow(0.0, -0.0) should be 1.0", 1.0, AccurateMath.pow(0.0, -0.0), EXACT);
413 assertEquals("pow(0.0, 0.0) should be 1.0", 1.0, AccurateMath.pow(0.0, 0.0), EXACT);
414 }
415
416 @Test(timeout = 20000L)
417 public void testPowAllSpecialCases() {
418 final double EXACT = -1.0;
419 final double[] DOUBLES = new double[] {
420 Double.NEGATIVE_INFINITY, -0.0, Double.NaN, 0.0, Double.POSITIVE_INFINITY,
421 Long.MIN_VALUE, Integer.MIN_VALUE, Short.MIN_VALUE, Byte.MIN_VALUE,
422 -(double)Long.MIN_VALUE, -(double)Integer.MIN_VALUE, -(double)Short.MIN_VALUE, -(double)Byte.MIN_VALUE,
423 Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE,
424 -Byte.MAX_VALUE, -Short.MAX_VALUE, -Integer.MAX_VALUE, -Long.MAX_VALUE,
425 Float.MAX_VALUE, Double.MAX_VALUE, Double.MIN_VALUE, Float.MIN_VALUE,
426 -Float.MAX_VALUE, -Double.MAX_VALUE, -Double.MIN_VALUE, -Float.MIN_VALUE,
427 0.5, 0.1, 0.2, 0.8, 1.1, 1.2, 1.5, 1.8, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1.3, 2.2, 2.5, 2.8, 33.0, 33.1, 33.5, 33.8, 10.0, 300.0, 400.0, 500.0,
428 -0.5, -0.1, -0.2, -0.8, -1.1, -1.2, -1.5, -1.8, -1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0, -8.0, -9.0, -1.3, -2.2, -2.5, -2.8, -33.0, -33.1, -33.5, -33.8, -10.0, -300.0, -400.0, -500.0
429 };
430
431
432
433 for (double d : DOUBLES) {
434 assertEquals(1.0, AccurateMath.pow(d, 0.0), EXACT);
435 }
436 for (double d : DOUBLES) {
437 assertEquals(1.0, AccurateMath.pow(d, -0.0), EXACT);
438 }
439
440 for (double d : DOUBLES) {
441 assertEquals(d, AccurateMath.pow(d, 1.0), EXACT);
442 }
443
444 for (double d : DOUBLES) {
445 assertEquals(Double.NaN, AccurateMath.pow(d, Double.NaN), EXACT);
446 }
447
448 for (double i : DOUBLES) {
449 if (i != 0.0) {
450 assertEquals(Double.NaN, AccurateMath.pow(Double.NaN, i), EXACT);
451 }
452 }
453
454
455 for (double d : DOUBLES) {
456 if (Math.abs(d) > 1.0) {
457 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(d, Double.POSITIVE_INFINITY), EXACT);
458 }
459 }
460 for (double d : DOUBLES) {
461 if (Math.abs(d) < 1.0) {
462 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(d, Double.NEGATIVE_INFINITY), EXACT);
463 }
464 }
465
466
467 for (double d : DOUBLES) {
468 if (Math.abs(d) > 1.0) {
469 assertEquals(0.0, AccurateMath.pow(d, Double.NEGATIVE_INFINITY), EXACT);
470 }
471 }
472 for (double d : DOUBLES) {
473 if (Math.abs(d) < 1.0) {
474 assertEquals(0.0, AccurateMath.pow(d, Double.POSITIVE_INFINITY), EXACT);
475 }
476 }
477
478 assertEquals(Double.NaN, AccurateMath.pow(1.0, Double.POSITIVE_INFINITY), EXACT);
479 assertEquals(Double.NaN, AccurateMath.pow(1.0, Double.NEGATIVE_INFINITY), EXACT);
480 assertEquals(Double.NaN, AccurateMath.pow(-1.0, Double.POSITIVE_INFINITY), EXACT);
481 assertEquals(Double.NaN, AccurateMath.pow(-1.0, Double.NEGATIVE_INFINITY), EXACT);
482
483
484 for (double i : DOUBLES) {
485 if (i > 0.0) {
486 assertEquals(0.0, AccurateMath.pow(0.0, i), EXACT);
487 }
488 }
489 for (double i : DOUBLES) {
490 if (i < 0.0) {
491 assertEquals(0.0, AccurateMath.pow(Double.POSITIVE_INFINITY, i), EXACT);
492 }
493 }
494
495
496 for (double i : DOUBLES) {
497 if (i < 0.0) {
498 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(0.0, i), EXACT);
499 }
500 }
501 for (double i : DOUBLES) {
502 if (i > 0.0) {
503 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(Double.POSITIVE_INFINITY, i), EXACT);
504 }
505 }
506
507
508 for (double i : DOUBLES) {
509 if (i > 0.0 && (Double.isInfinite(i) || i % 2.0 == 0.0)) {
510 assertEquals(0.0, AccurateMath.pow(-0.0, i), EXACT);
511 }
512 }
513 for (double i : DOUBLES) {
514 if (i < 0.0 && (Double.isInfinite(i) || i % 2.0 == 0.0)) {
515 assertEquals(0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
516 }
517 }
518
519
520 for (double i : DOUBLES) {
521 if (i > 0.0 && i % 2.0 == 1.0) {
522 assertEquals(-0.0, AccurateMath.pow(-0.0, i), EXACT);
523 }
524 }
525 for (double i : DOUBLES) {
526 if (i < 0.0 && i % 2.0 == -1.0) {
527 assertEquals(-0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
528 }
529 }
530
531
532 for (double i : DOUBLES) {
533 if (i > 0.0 && (Double.isInfinite(i) || i % 2.0 == 0.0)) {
534 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
535 }
536 }
537 for (double i : DOUBLES) {
538 if (i < 0.0 && (Double.isInfinite(i) || i % 2.0 == 0.0)) {
539 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(-0.0, i), EXACT);
540 }
541 }
542
543
544 for (double i : DOUBLES) {
545 if (i > 0.0 && i % 2.0 == 1.0) {
546 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
547 }
548 }
549 for (double i : DOUBLES) {
550 if (i < 0.0 && i % 2.0 == -1.0) {
551 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.pow(-0.0, i), EXACT);
552 }
553 }
554 for (double d : DOUBLES) {
555
556 if (d < 0.0 && Math.abs(d) <= Double.MAX_VALUE) {
557 for (double i : DOUBLES) {
558 if (Math.abs(i) <= Double.MAX_VALUE) {
559
560 if (i % 2.0 == 0.0) {
561 assertEquals(AccurateMath.pow(-d, i), AccurateMath.pow(d, i), EXACT);
562 } else if (Math.abs(i) % 2.0 == 1.0) {
563
564 assertEquals(-AccurateMath.pow(-d, i), AccurateMath.pow(d, i), EXACT);
565 } else {
566
567 assertEquals(Double.NaN, AccurateMath.pow(d, i), EXACT);
568 }
569 }
570 }
571 }
572 }
573
574
575 final int TOO_BIG_TO_CALCULATE = 18;
576 for (double d : DOUBLES) {
577 if (d % 1.0 == 0.0) {
578 boolean dNegative = Double.doubleToRawLongBits(d) < 0L;
579 for (double i : DOUBLES) {
580 if (i % 1.0 == 0.0) {
581 BigInteger bd = BigDecimal.valueOf(d).toBigInteger().abs();
582 BigInteger bi = BigDecimal.valueOf(i).toBigInteger().abs();
583 double expected;
584 if (bd.bitLength() > 1 && bi.bitLength() > 1 && 32 - Integer.numberOfLeadingZeros(bd.bitLength()) + bi.bitLength() > TOO_BIG_TO_CALCULATE) {
585
586 expected = i < 0.0 ? 0.0 : Double.POSITIVE_INFINITY;
587 } else {
588 BigInteger res = ArithmeticUtils.pow(bd, bi);
589 if (i >= 0.0) {
590 expected = res.doubleValue();
591 } else if (res.signum() == 0) {
592 expected = Double.POSITIVE_INFINITY;
593 } else {
594 expected = BigDecimal.ONE.divide(new BigDecimal(res), 1024, RoundingMode.HALF_UP).doubleValue();
595 }
596 }
597 if (dNegative && bi.testBit(0)) {
598 expected = -expected;
599 }
600 assertEquals(d + "^" + i + "=" + expected + ", Math.pow=" + Math.pow(d, i), expected, AccurateMath.pow(d, i), expected == 0.0 || Double.isInfinite(expected) || Double.isNaN(expected) ? EXACT : 2.0 * Math.ulp(expected));
601 }
602 }
603 }
604 }
605 }
606
607 @Test
608 public void testPowLargeIntegralDouble() {
609 double y = AccurateMath.scalb(1.0, 65);
610 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(AccurateMath.nextUp(1.0), y), 1.0);
611 assertEquals(1.0, AccurateMath.pow(1.0, y), 1.0);
612 assertEquals(0.0, AccurateMath.pow(AccurateMath.nextDown(1.0), y), 1.0);
613 assertEquals(0.0, AccurateMath.pow(AccurateMath.nextUp(-1.0), y), 1.0);
614 assertEquals(1.0, AccurateMath.pow(-1.0, y), 1.0);
615 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(AccurateMath.nextDown(-1.0), y), 1.0);
616 }
617
618 @Test
619 public void testAtan2SpecialCases() {
620
621 assertTrue("atan2(NaN, 0.0) should be NaN", Double.isNaN(AccurateMath.atan2(Double.NaN, 0.0)));
622 assertTrue("atan2(0.0, NaN) should be NaN", Double.isNaN(AccurateMath.atan2(0.0, Double.NaN)));
623
624 final double pinf = Double.POSITIVE_INFINITY;
625 final double ninf = Double.NEGATIVE_INFINITY;
626
627 assertAtan2(+0.0, 0.0, 0.0, 1.0);
628 assertAtan2(+0.0, -0.0, 1.0, 1.0);
629 assertAtan2(+0.0, 0.1, 0.0, 1.0);
630 assertAtan2(+0.0, -0.1, 1.0, 1.0);
631 assertAtan2(+0.0, pinf, 0.0, 1.0);
632 assertAtan2(+0.0, ninf, 1.0, 1.0);
633 assertAtan2(-0.0, 0.0, -0.0, 1.0);
634 assertAtan2(-0.0, -0.0, -1.0, 1.0);
635 assertAtan2(-0.0, 0.1, -0.0, 1.0);
636 assertAtan2(-0.0, -0.1, -1.0, 1.0);
637 assertAtan2(-0.0, pinf, -0.0, 1.0);
638 assertAtan2(-0.0, ninf, -1.0, 1.0);
639 assertAtan2(+0.1, 0.0, 1.0, 2.0);
640 assertAtan2(+0.1, -0.0, 1.0, 2.0);
641 assertAtan2(+0.1, 0.1, 1.0, 4.0);
642 assertAtan2(+0.1, -0.1, 3.0, 4.0);
643 assertAtan2(+0.1, pinf, 0.0, 1.0);
644 assertAtan2(+0.1, ninf, 1.0, 1.0);
645 assertAtan2(-0.1, 0.0, -1.0, 2.0);
646 assertAtan2(-0.1, -0.0, -1.0, 2.0);
647 assertAtan2(-0.1, 0.1, -1.0, 4.0);
648 assertAtan2(-0.1, -0.1, -3.0, 4.0);
649 assertAtan2(-0.1, pinf, -0.0, 1.0);
650 assertAtan2(-0.1, ninf, -1.0, 1.0);
651 assertAtan2(pinf, 0.0, 1.0, 2.0);
652 assertAtan2(pinf, -0.0, 1.0, 2.0);
653 assertAtan2(pinf, 0.1, 1.0, 2.0);
654 assertAtan2(pinf, -0.1, 1.0, 2.0);
655 assertAtan2(pinf, pinf, 1.0, 4.0);
656 assertAtan2(pinf, ninf, 3.0, 4.0);
657 assertAtan2(ninf, 0.0, -1.0, 2.0);
658 assertAtan2(ninf, -0.0, -1.0, 2.0);
659 assertAtan2(ninf, 0.1, -1.0, 2.0);
660 assertAtan2(ninf, -0.1, -1.0, 2.0);
661 assertAtan2(ninf, pinf, -1.0, 4.0);
662 assertAtan2(ninf, ninf, -3.0, 4.0);
663 }
664
665
666
667
668
669
670
671
672
673 private static void assertAtan2(double y, double x, double numerator, double denominator) {
674 final double v = AccurateMath.atan2(y, x);
675 if (numerator == 0) {
676
677 Assertions.assertEquals(numerator, v,
678 () -> String.format("atan2(%s, %s) should be %s but was %s", y, x, numerator, v));
679 } else {
680 final double expected = AccurateMath.PI * numerator / denominator;
681 Assertions.assertEquals(expected, v, Precision.EPSILON,
682 () -> String.format("atan2(%s, %s) should be pi * %s / %s", y, x, numerator, denominator));
683 }
684 }
685
686 @Test
687 public void testPowAccuracy() {
688 double maxerrulp = 0.0;
689
690 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
691 double x = (generator.nextDouble() * 2.0 + 0.25);
692 double y = (generator.nextDouble() * 1200.0 - 600.0) * generator.nextDouble();
693
694
695
696
697
698
699
700
701 double tst = AccurateMath.pow(x, y);
702 double ref = DfpMath.pow(field.newDfp(x), field.newDfp(y)).toDouble();
703 double err = (tst - ref) / ref;
704
705 if (err != 0) {
706 double ulp = Math.abs(ref -
707 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
708 double errulp = field.newDfp(tst).subtract(DfpMath.pow(field.newDfp(x), field.newDfp(y))).divide(field.newDfp(ulp)).toDouble();
709
710
711 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
712 }
713 }
714
715 assertTrue("pow() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
716 }
717
718 @Test
719 public void testExpAccuracy() {
720 double maxerrulp = 0.0;
721
722 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
723
724 double x = ((generator.nextDouble() * 1416.0) - 708.0) * generator.nextDouble();
725
726
727
728 double tst = AccurateMath.exp(x);
729 double ref = DfpMath.exp(field.newDfp(x)).toDouble();
730 double err = (tst - ref) / ref;
731
732 if (err != 0) {
733 double ulp = Math.abs(ref -
734 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
735 double errulp = field.newDfp(tst).subtract(DfpMath.exp(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
736
737
738 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
739 }
740 }
741
742 assertTrue("exp() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
743 }
744
745 @Test
746 public void testSinAccuracy() {
747 double maxerrulp = 0.0;
748
749 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
750
751
752 double x = ((generator.nextDouble() * Math.PI) - Math.PI / 2.0) *
753 Math.pow(2, 21) * generator.nextDouble();
754
755
756
757 double tst = AccurateMath.sin(x);
758 double ref = DfpMath.sin(field.newDfp(x)).toDouble();
759 double err = (tst - ref) / ref;
760
761 if (err != 0) {
762 double ulp = Math.abs(ref -
763 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
764 double errulp = field.newDfp(tst).subtract(DfpMath.sin(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
765
766
767 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
768 }
769 }
770
771 assertTrue("sin() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
772 }
773
774 @Test
775 public void testCosAccuracy() {
776 double maxerrulp = 0.0;
777
778 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
779
780
781 double x = ((generator.nextDouble() * Math.PI) - Math.PI / 2.0) *
782 Math.pow(2, 21) * generator.nextDouble();
783
784
785
786 double tst = AccurateMath.cos(x);
787 double ref = DfpMath.cos(field.newDfp(x)).toDouble();
788 double err = (tst - ref) / ref;
789
790 if (err != 0) {
791 double ulp = Math.abs(ref -
792 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
793 double errulp = field.newDfp(tst).subtract(DfpMath.cos(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
794
795
796 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
797 }
798 }
799
800 assertTrue("cos() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
801 }
802
803 @Test
804 public void testTanAccuracy() {
805 double maxerrulp = 0.0;
806
807 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
808
809
810 double x = ((generator.nextDouble() * Math.PI) - Math.PI / 2.0) *
811 Math.pow(2, 12) * generator.nextDouble();
812
813
814
815 double tst = AccurateMath.tan(x);
816 double ref = DfpMath.tan(field.newDfp(x)).toDouble();
817 double err = (tst - ref) / ref;
818
819 if (err != 0) {
820 double ulp = Math.abs(ref -
821 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
822 double errulp = field.newDfp(tst).subtract(DfpMath.tan(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
823
824
825 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
826 }
827 }
828
829 assertTrue("tan() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
830 }
831
832 @Test
833 public void testAtanAccuracy() {
834 double maxerrulp = 0.0;
835
836 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
837
838
839
840
841 double x = ((generator.nextDouble() * 16.0) - 8.0) * generator.nextDouble();
842
843
844
845
846 double tst = AccurateMath.atan(x);
847 double ref = DfpMath.atan(field.newDfp(x)).toDouble();
848 double err = (tst - ref) / ref;
849
850 if (err != 0) {
851 double ulp = Math.abs(ref -
852 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
853 double errulp = field.newDfp(tst).subtract(DfpMath.atan(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
854
855
856 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
857 }
858 }
859
860 assertTrue("atan() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
861 }
862
863 @Test
864 public void testAtan2Accuracy() {
865 double maxerrulp = 0.0;
866
867 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
868
869
870 double x = generator.nextDouble() - 0.5;
871 double y = generator.nextDouble() - 0.5;
872
873
874
875 double tst = AccurateMath.atan2(y, x);
876 Dfp refdfp = DfpMath.atan(field.newDfp(y).divide(field.newDfp(x)));
877
878 if (x < 0.0) {
879 if (y > 0.0) {
880 refdfp = field.getPi().add(refdfp);
881 } else {
882 refdfp = refdfp.subtract(field.getPi());
883 }
884 }
885
886 double ref = refdfp.toDouble();
887 double err = (tst - ref) / ref;
888
889 if (err != 0) {
890 double ulp = Math.abs(ref -
891 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
892 double errulp = field.newDfp(tst).subtract(refdfp).divide(field.newDfp(ulp)).toDouble();
893
894
895 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
896 }
897 }
898
899 assertTrue("atan2() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
900 }
901
902 @Test
903 public void testExpm1Accuracy() {
904 double maxerrulp = 0.0;
905
906 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
907
908
909 double x = ((generator.nextDouble() * 16.0) - 8.0) * generator.nextDouble();
910
911 double tst = AccurateMath.expm1(x);
912 double ref = DfpMath.exp(field.newDfp(x)).subtract(field.getOne()).toDouble();
913 double err = (tst - ref) / ref;
914
915 if (err != 0) {
916 double ulp = Math.abs(ref -
917 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
918 double errulp = field.newDfp(tst).subtract(DfpMath.exp(field.newDfp(x)).subtract(field.getOne())).divide(field.newDfp(ulp)).toDouble();
919
920
921 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
922 }
923 }
924
925 assertTrue("expm1() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
926 }
927
928 @Test
929 public void testAsinAccuracy() {
930 double maxerrulp = 0.0;
931
932 for (int i = 0; i < 10000; i++) {
933 double x = ((generator.nextDouble() * 2.0) - 1.0) * generator.nextDouble();
934
935 double tst = AccurateMath.asin(x);
936 double ref = DfpMath.asin(field.newDfp(x)).toDouble();
937 double err = (tst - ref) / ref;
938
939 if (err != 0) {
940 double ulp = Math.abs(ref - Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
941 double errulp = field.newDfp(tst).subtract(DfpMath.asin(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
942
943
944 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
945 }
946 }
947
948 assertTrue("asin() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
949 }
950
951 @Test
952 public void testAcosAccuracy() {
953 double maxerrulp = 0.0;
954
955 for (int i = 0; i < 10000; i++) {
956 double x = ((generator.nextDouble() * 2.0) - 1.0) * generator.nextDouble();
957
958 double tst = AccurateMath.acos(x);
959 double ref = DfpMath.acos(field.newDfp(x)).toDouble();
960 double err = (tst - ref) / ref;
961
962 if (err != 0) {
963 double ulp = Math.abs(ref - Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
964 double errulp = field.newDfp(tst).subtract(DfpMath.acos(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
965
966
967 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
968 }
969 }
970
971 assertTrue("acos() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
972 }
973
974
975
976
977 @Test
978 public void testAcosSpecialCases() {
979
980 assertTrue("acos(NaN) should be NaN", Double.isNaN(AccurateMath.acos(Double.NaN)));
981 assertTrue("acos(-1.1) should be NaN", Double.isNaN(AccurateMath.acos(-1.1)));
982 assertTrue("acos(-1.1) should be NaN", Double.isNaN(AccurateMath.acos(1.1)));
983 assertEquals("acos(-1.0) should be PI", AccurateMath.acos(-1.0), AccurateMath.PI, Precision.EPSILON);
984 assertEquals("acos(1.0) should be 0.0", AccurateMath.acos(1.0), 0.0, Precision.EPSILON);
985 assertEquals("acos(0.0) should be PI/2", AccurateMath.acos(0.0), AccurateMath.PI / 2.0, Precision.EPSILON);
986 }
987
988
989
990
991 @Test
992 public void testAsinSpecialCases() {
993
994 assertTrue("asin(NaN) should be NaN", Double.isNaN(AccurateMath.asin(Double.NaN)));
995 assertTrue("asin(1.1) should be NaN", Double.isNaN(AccurateMath.asin(1.1)));
996 assertTrue("asin(-1.1) should be NaN", Double.isNaN(AccurateMath.asin(-1.1)));
997 assertEquals("asin(1.0) should be PI/2", AccurateMath.asin(1.0), AccurateMath.PI / 2.0, Precision.EPSILON);
998 assertEquals("asin(-1.0) should be -PI/2", AccurateMath.asin(-1.0), -AccurateMath.PI / 2.0, Precision.EPSILON);
999 assertEquals("asin(0.0) should be 0.0", AccurateMath.asin(0.0), 0.0, Precision.EPSILON);
1000 }
1001
1002 private Dfp cosh(Dfp x) {
1003 return DfpMath.exp(x).add(DfpMath.exp(x.negate())).divide(2);
1004 }
1005
1006 private Dfp sinh(Dfp x) {
1007 return DfpMath.exp(x).subtract(DfpMath.exp(x.negate())).divide(2);
1008 }
1009
1010 private Dfp tanh(Dfp x) {
1011 return sinh(x).divide(cosh(x));
1012 }
1013
1014 @Test
1015 public void testSinhAccuracy() {
1016 double maxerrulp = 0.0;
1017
1018 for (int i = 0; i < 10000; i++) {
1019 double x = ((generator.nextDouble() * 16.0) - 8.0) * generator.nextDouble();
1020
1021 double tst = AccurateMath.sinh(x);
1022 double ref = sinh(field.newDfp(x)).toDouble();
1023 double err = (tst - ref) / ref;
1024
1025 if (err != 0) {
1026 double ulp = Math.abs(ref - Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
1027 double errulp = field.newDfp(tst).subtract(sinh(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
1028
1029 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
1030 }
1031 }
1032
1033 assertTrue("sinh() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
1034 }
1035
1036 @Test
1037 public void testCoshAccuracy() {
1038 double maxerrulp = 0.0;
1039
1040 for (int i = 0; i < 10000; i++) {
1041 double x = ((generator.nextDouble() * 16.0) - 8.0) * generator.nextDouble();
1042
1043 double tst = AccurateMath.cosh(x);
1044 double ref = cosh(field.newDfp(x)).toDouble();
1045 double err = (tst - ref) / ref;
1046
1047 if (err != 0) {
1048 double ulp = Math.abs(ref - Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
1049 double errulp = field.newDfp(tst).subtract(cosh(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
1050
1051 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
1052 }
1053 }
1054
1055 assertTrue("cosh() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
1056 }
1057
1058 @Test
1059 public void testTanhAccuracy() {
1060 double maxerrulp = 0.0;
1061
1062 for (int i = 0; i < 10000; i++) {
1063 double x = ((generator.nextDouble() * 16.0) - 8.0) * generator.nextDouble();
1064
1065 double tst = AccurateMath.tanh(x);
1066 double ref = tanh(field.newDfp(x)).toDouble();
1067 double err = (tst - ref) / ref;
1068
1069 if (err != 0) {
1070 double ulp = Math.abs(ref - Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
1071 double errulp = field.newDfp(tst).subtract(tanh(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
1072
1073 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
1074 }
1075 }
1076
1077 assertTrue("tanh() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
1078 }
1079
1080 @Test
1081 public void testCbrtAccuracy() {
1082 double maxerrulp = 0.0;
1083
1084 for (int i = 0; i < 10000; i++) {
1085 double x = ((generator.nextDouble() * 200.0) - 100.0) * generator.nextDouble();
1086
1087 double tst = AccurateMath.cbrt(x);
1088 double ref = cbrt(field.newDfp(x)).toDouble();
1089 double err = (tst - ref) / ref;
1090
1091 if (err != 0) {
1092 double ulp = Math.abs(ref - Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
1093 double errulp = field.newDfp(tst).subtract(cbrt(field.newDfp(x))).divide(field.newDfp(ulp)).toDouble();
1094
1095 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
1096 }
1097 }
1098
1099 assertTrue("cbrt() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
1100 }
1101
1102 private Dfp cbrt(Dfp x) {
1103 boolean negative = false;
1104
1105 if (x.lessThan(field.getZero())) {
1106 negative = true;
1107 x = x.negate();
1108 }
1109
1110 Dfp y = DfpMath.pow(x, field.getOne().divide(3));
1111
1112 if (negative) {
1113 y = y.negate();
1114 }
1115
1116 return y;
1117 }
1118
1119 @Test
1120 public void testToDegrees() {
1121 double maxerrulp = 0.0;
1122 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
1123 double x = generator.nextDouble();
1124 double tst = field.newDfp(x).multiply(180).divide(field.getPi()).toDouble();
1125 double ref = AccurateMath.toDegrees(x);
1126 double err = (tst - ref) / ref;
1127
1128 if (err != 0) {
1129 double ulp = Math.abs(ref -
1130 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
1131 double errulp = field.newDfp(tst).subtract(DfpMath.exp(field.newDfp(x)).subtract(field.getOne())).divide(field.newDfp(ulp)).toDouble();
1132
1133
1134 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
1135 }
1136 }
1137 assertTrue("toDegrees() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
1138 }
1139
1140 @Test
1141 public void testToRadians() {
1142 double maxerrulp = 0.0;
1143 for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
1144 double x = generator.nextDouble();
1145 double tst = field.newDfp(x).multiply(field.getPi()).divide(180).toDouble();
1146 double ref = AccurateMath.toRadians(x);
1147 double err = (tst - ref) / ref;
1148
1149 if (err != 0) {
1150 double ulp = Math.abs(ref -
1151 Double.longBitsToDouble((Double.doubleToLongBits(ref) ^ 1)));
1152 double errulp = field.newDfp(tst).subtract(DfpMath.exp(field.newDfp(x)).subtract(field.getOne())).divide(field.newDfp(ulp)).toDouble();
1153
1154
1155 maxerrulp = Math.max(maxerrulp, Math.abs(errulp));
1156 }
1157 }
1158
1159 assertTrue("toRadians() had errors in excess of " + MAX_ERROR_ULP + " ULP", maxerrulp < MAX_ERROR_ULP);
1160 }
1161
1162 @Test
1163 public void testNextAfter() {
1164
1165 assertEquals(16.0, AccurateMath.nextUp(15.999999999999998), 0.0);
1166
1167
1168 assertEquals(-15.999999999999996, AccurateMath.nextAfter(-15.999999999999998, 34.27555555555555), 0.0);
1169
1170
1171 assertEquals(15.999999999999996, AccurateMath.nextDown(15.999999999999998), 0.0);
1172
1173
1174 assertEquals(-15.999999999999996, AccurateMath.nextAfter(-15.999999999999998, 2.142222222222222), 0.0);
1175
1176
1177 assertEquals(8.000000000000002, AccurateMath.nextAfter(8.0, 34.27555555555555), 0.0);
1178
1179
1180 assertEquals(-7.999999999999999, AccurateMath.nextAfter(-8.0, 34.27555555555555), 0.0);
1181
1182
1183 assertEquals(7.999999999999999, AccurateMath.nextAfter(8.0, 2.142222222222222), 0.0);
1184
1185
1186 assertEquals(-7.999999999999999, AccurateMath.nextAfter(-8.0, 2.142222222222222), 0.0);
1187
1188
1189 assertEquals(2.308922399667661E-4, AccurateMath.nextAfter(2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
1190
1191
1192 assertEquals(2.3089223996676606E-4, AccurateMath.nextAfter(2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
1193
1194
1195 assertEquals(2.3089223996676603E-4, AccurateMath.nextAfter(2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
1196
1197
1198 assertEquals(2.3089223996676603E-4, AccurateMath.nextAfter(2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
1199
1200
1201 assertEquals(2.3089223996676603E-4, AccurateMath.nextAfter(2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
1202
1203
1204 assertEquals(2.3089223996676603E-4, AccurateMath.nextAfter(2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
1205
1206
1207 assertEquals(-2.3089223996676603E-4, AccurateMath.nextAfter(-2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
1208
1209
1210 assertEquals(-2.3089223996676603E-4, AccurateMath.nextAfter(-2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
1211
1212
1213 assertEquals(-2.3089223996676603E-4, AccurateMath.nextAfter(-2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
1214
1215
1216 assertEquals(-2.308922399667661E-4, AccurateMath.nextAfter(-2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
1217
1218
1219 assertEquals(-2.3089223996676606E-4, AccurateMath.nextAfter(-2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
1220
1221
1222 assertEquals(-2.3089223996676603E-4, AccurateMath.nextAfter(-2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
1223 }
1224
1225 @Test
1226 public void testDoubleNextAfterSpecialCases() {
1227 assertEquals(-Double.MAX_VALUE, AccurateMath.nextAfter(Double.NEGATIVE_INFINITY, 0D), 0D);
1228 assertEquals(Double.MAX_VALUE, AccurateMath.nextAfter(Double.POSITIVE_INFINITY, 0D), 0D);
1229 assertEquals(Double.NaN, AccurateMath.nextAfter(Double.NaN, 0D), 0D);
1230 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.nextAfter(Double.MAX_VALUE, Double.POSITIVE_INFINITY), 0D);
1231 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.nextAfter(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY), 0D);
1232 assertEquals(Double.MIN_VALUE, AccurateMath.nextAfter(0D, 1D), 0D);
1233 assertEquals(-Double.MIN_VALUE, AccurateMath.nextAfter(0D, -1D), 0D);
1234 assertEquals(0D, AccurateMath.nextAfter(Double.MIN_VALUE, -1), 0D);
1235 assertEquals(0D, AccurateMath.nextAfter(-Double.MIN_VALUE, 1), 0D);
1236 }
1237
1238 @Test
1239 public void testFloatNextAfterSpecialCases() {
1240 assertEquals(-Float.MAX_VALUE, AccurateMath.nextAfter(Float.NEGATIVE_INFINITY, 0F), 0F);
1241 assertEquals(Float.MAX_VALUE, AccurateMath.nextAfter(Float.POSITIVE_INFINITY, 0F), 0F);
1242 assertEquals(Float.NaN, AccurateMath.nextAfter(Float.NaN, 0F), 0F);
1243 assertEquals(Float.POSITIVE_INFINITY, AccurateMath.nextUp(Float.MAX_VALUE), 0F);
1244 assertEquals(Float.NEGATIVE_INFINITY, AccurateMath.nextDown(-Float.MAX_VALUE), 0F);
1245 assertEquals(Float.MIN_VALUE, AccurateMath.nextAfter(0F, 1F), 0F);
1246 assertEquals(-Float.MIN_VALUE, AccurateMath.nextAfter(0F, -1F), 0F);
1247 assertEquals(0F, AccurateMath.nextAfter(Float.MIN_VALUE, -1F), 0F);
1248 assertEquals(0F, AccurateMath.nextAfter(-Float.MIN_VALUE, 1F), 0F);
1249 }
1250
1251 @Test
1252 public void testDoubleScalbSpecialCases() {
1253 assertEquals(2.5269841324701218E-175, AccurateMath.scalb(2.2250738585072014E-308, 442), 0D);
1254 assertEquals(1.307993905256674E297, AccurateMath.scalb(1.1102230246251565E-16, 1040), 0D);
1255 assertEquals(7.2520887996488946E-217, AccurateMath.scalb(Double.MIN_VALUE, 356), 0D);
1256 assertEquals(8.98846567431158E307, AccurateMath.scalb(Double.MIN_VALUE, 2097), 0D);
1257 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.scalb(Double.MIN_VALUE, 2098), 0D);
1258 assertEquals(1.1125369292536007E-308, AccurateMath.scalb(2.225073858507201E-308, -1), 0D);
1259 assertEquals(1.0E-323, AccurateMath.scalb(Double.MAX_VALUE, -2097), 0D);
1260 assertEquals(Double.MIN_VALUE, AccurateMath.scalb(Double.MAX_VALUE, -2098), 0D);
1261 assertEquals(0, AccurateMath.scalb(Double.MAX_VALUE, -2099), 0D);
1262 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.scalb(Double.POSITIVE_INFINITY, -1000000), 0D);
1263 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.scalb(-1.1102230246251565E-16, 1078), 0D);
1264 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.scalb(-1.1102230246251565E-16, 1079), 0D);
1265 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.scalb(-2.2250738585072014E-308, 2047), 0D);
1266 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.scalb(-2.2250738585072014E-308, 2048), 0D);
1267 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.scalb(-1.7976931348623157E308, 2147483647), 0D);
1268 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.scalb(+1.7976931348623157E308, 2147483647), 0D);
1269 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.scalb(-1.1102230246251565E-16, 2147483647), 0D);
1270 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.scalb(+1.1102230246251565E-16, 2147483647), 0D);
1271 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.scalb(-2.2250738585072014E-308, 2147483647), 0D);
1272 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.scalb(+2.2250738585072014E-308, 2147483647), 0D);
1273 }
1274
1275 @Test
1276 public void testFloatScalbSpecialCases() {
1277 assertEquals(0f, AccurateMath.scalb(Float.MIN_VALUE, -30), 0F);
1278 assertEquals(2 * Float.MIN_VALUE, AccurateMath.scalb(Float.MIN_VALUE, 1), 0F);
1279 assertEquals(7.555786e22f, AccurateMath.scalb(Float.MAX_VALUE, -52), 0F);
1280 assertEquals(1.7014118e38f, AccurateMath.scalb(Float.MIN_VALUE, 276), 0F);
1281 assertEquals(Float.POSITIVE_INFINITY, AccurateMath.scalb(Float.MIN_VALUE, 277), 0F);
1282 assertEquals(5.8774718e-39f, AccurateMath.scalb(1.1754944e-38f, -1), 0F);
1283 assertEquals(2 * Float.MIN_VALUE, AccurateMath.scalb(Float.MAX_VALUE, -276), 0F);
1284 assertEquals(Float.MIN_VALUE, AccurateMath.scalb(Float.MAX_VALUE, -277), 0F);
1285 assertEquals(0, AccurateMath.scalb(Float.MAX_VALUE, -278), 0F);
1286 assertEquals(Float.POSITIVE_INFINITY, AccurateMath.scalb(Float.POSITIVE_INFINITY, -1000000), 0F);
1287 assertEquals(-3.13994498e38f, AccurateMath.scalb(-1.1e-7f, 151), 0F);
1288 assertEquals(Float.NEGATIVE_INFINITY, AccurateMath.scalb(-1.1e-7f, 152), 0F);
1289 assertEquals(Float.POSITIVE_INFINITY, AccurateMath.scalb(3.4028235E38f, 2147483647), 0F);
1290 assertEquals(Float.NEGATIVE_INFINITY, AccurateMath.scalb(-3.4028235E38f, 2147483647), 0F);
1291 }
1292
1293 @Test
1294 public void testSignumDouble() {
1295 final double delta = 0.0;
1296 assertEquals(1.0, AccurateMath.signum(2.0), delta);
1297 assertEquals(0.0, AccurateMath.signum(0.0), delta);
1298 assertEquals(-1.0, AccurateMath.signum(-2.0), delta);
1299 Assert.assertTrue(Double.isNaN(AccurateMath.signum(Double.NaN)));
1300 }
1301
1302 @Test
1303 public void testSignumFloat() {
1304 final float delta = 0.0F;
1305 assertEquals(1.0F, AccurateMath.signum(2.0F), delta);
1306 assertEquals(0.0F, AccurateMath.signum(0.0F), delta);
1307 assertEquals(-1.0F, AccurateMath.signum(-2.0F), delta);
1308 Assert.assertTrue(Double.isNaN(AccurateMath.signum(Float.NaN)));
1309 }
1310
1311 @Test
1312 public void testLogWithBase() {
1313 assertEquals(2.0, AccurateMath.log(2, 4), 0);
1314 assertEquals(3.0, AccurateMath.log(2, 8), 0);
1315 assertTrue(Double.isNaN(AccurateMath.log(-1, 1)));
1316 assertTrue(Double.isNaN(AccurateMath.log(1, -1)));
1317 assertTrue(Double.isNaN(AccurateMath.log(0, 0)));
1318 assertEquals(0, AccurateMath.log(0, 10), 0);
1319 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.log(10, 0), 0);
1320 }
1321
1322 @Test
1323 public void testIndicatorDouble() {
1324 double delta = 0.0;
1325 assertEquals(1.0, AccurateMath.copySign(1d, 2.0), delta);
1326 assertEquals(1.0, AccurateMath.copySign(1d, 0.0), delta);
1327 assertEquals(-1.0, AccurateMath.copySign(1d, -0.0), delta);
1328 assertEquals(1.0, AccurateMath.copySign(1d, Double.POSITIVE_INFINITY), delta);
1329 assertEquals(-1.0, AccurateMath.copySign(1d, Double.NEGATIVE_INFINITY), delta);
1330 assertEquals(1.0, AccurateMath.copySign(1d, Double.NaN), delta);
1331 assertEquals(-1.0, AccurateMath.copySign(1d, -2.0), delta);
1332 }
1333
1334 @Test
1335 public void testIndicatorFloat() {
1336 float delta = 0.0F;
1337 assertEquals(1.0F, AccurateMath.copySign(1d, 2.0F), delta);
1338 assertEquals(1.0F, AccurateMath.copySign(1d, 0.0F), delta);
1339 assertEquals(-1.0F, AccurateMath.copySign(1d, -0.0F), delta);
1340 assertEquals(1.0F, AccurateMath.copySign(1d, Float.POSITIVE_INFINITY), delta);
1341 assertEquals(-1.0F, AccurateMath.copySign(1d, Float.NEGATIVE_INFINITY), delta);
1342 assertEquals(1.0F, AccurateMath.copySign(1d, Float.NaN), delta);
1343 assertEquals(-1.0F, AccurateMath.copySign(1d, -2.0F), delta);
1344 }
1345
1346 @Test
1347 public void testIntPow() {
1348 final int maxExp = 300;
1349 DfpField localField = new DfpField(40);
1350 final double base = 1.23456789;
1351 Dfp baseDfp = localField.newDfp(base);
1352 Dfp dfpPower = localField.getOne();
1353 for (int i = 0; i < maxExp; i++) {
1354 assertEquals("exp=" + i, dfpPower.toDouble(), AccurateMath.pow(base, i),
1355 0.6 * AccurateMath.ulp(dfpPower.toDouble()));
1356 dfpPower = dfpPower.multiply(baseDfp);
1357 }
1358 }
1359
1360 @Test
1361 public void testIntPowHuge() {
1362 assertTrue(Double.isInfinite(AccurateMath.pow(AccurateMath.scalb(1.0, 500), 4)));
1363 }
1364
1365 @Test(timeout = 5000L)
1366 public void testIntPowLongMinValue() {
1367 assertEquals(1.0, AccurateMath.pow(1.0, Long.MIN_VALUE), -1.0);
1368 }
1369
1370 @Test(timeout = 5000L)
1371 public void testIntPowSpecialCases() {
1372 final double EXACT = -1.0;
1373 final double[] DOUBLES = new double[] {
1374 Double.NEGATIVE_INFINITY, -0.0, Double.NaN, 0.0, Double.POSITIVE_INFINITY,
1375 Long.MIN_VALUE, Integer.MIN_VALUE, Short.MIN_VALUE, Byte.MIN_VALUE,
1376 -(double)Long.MIN_VALUE, -(double)Integer.MIN_VALUE, -(double)Short.MIN_VALUE, -(double)Byte.MIN_VALUE,
1377 Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE,
1378 -Byte.MAX_VALUE, -Short.MAX_VALUE, -Integer.MAX_VALUE, -Long.MAX_VALUE,
1379 Float.MAX_VALUE, Double.MAX_VALUE, Double.MIN_VALUE, Float.MIN_VALUE,
1380 -Float.MAX_VALUE, -Double.MAX_VALUE, -Double.MIN_VALUE, -Float.MIN_VALUE,
1381 0.5, 0.1, 0.2, 0.8, 1.1, 1.2, 1.5, 1.8, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1.3, 2.2, 2.5, 2.8, 33.0, 33.1, 33.5, 33.8, 10.0, 300.0, 400.0, 500.0,
1382 -0.5, -0.1, -0.2, -0.8, -1.1, -1.2, -1.5, -1.8, -1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0, -8.0, -9.0, -1.3, -2.2, -2.5, -2.8, -33.0, -33.1, -33.5, -33.8, -10.0, -300.0, -400.0, -500.0
1383 };
1384
1385 final long[] INTS = new long[]{Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 2, Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2, 0, 1, 2, 3, 5, 8, 10, 20, 100, 300, 500, -1, -2, -3, -5, -8, -10, -20, -100, -300, -500};
1386
1387
1388 for (double d : DOUBLES) {
1389 assertEquals(1.0, AccurateMath.pow(d, 0L), EXACT);
1390 }
1391
1392 for (double d : DOUBLES) {
1393 assertEquals(d, AccurateMath.pow(d, 1L), EXACT);
1394 }
1395
1396
1397 for (long i : INTS) {
1398 if (i != 0L) {
1399 assertEquals(Double.NaN, AccurateMath.pow(Double.NaN, i), EXACT);
1400 }
1401 }
1402
1403
1404 for (double d : DOUBLES) {
1405 if (Math.abs(d) > 1.0) {
1406 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(d, Long.MAX_VALUE - 1L), EXACT);
1407 }
1408 }
1409 for (double d : DOUBLES) {
1410 if (Math.abs(d) < 1.0) {
1411 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(d, Long.MIN_VALUE), EXACT);
1412 }
1413 }
1414
1415 for (double d : DOUBLES) {
1416 if (Math.abs(d) > 1.0) {
1417 assertTrue(Double.isInfinite(AccurateMath.pow(d, Long.MAX_VALUE)));
1418 }
1419 }
1420 for (double d : DOUBLES) {
1421 if (Math.abs(d) < 1.0) {
1422 assertTrue(Double.isInfinite(AccurateMath.pow(d, Long.MIN_VALUE + 1L)));
1423 }
1424 }
1425
1426
1427 for (double d : DOUBLES) {
1428 if (Math.abs(d) > 1.0) {
1429 assertEquals(0.0, AccurateMath.pow(d, Long.MIN_VALUE), EXACT);
1430 }
1431 }
1432 for (double d : DOUBLES) {
1433 if (Math.abs(d) < 1.0) {
1434 assertEquals(0.0, AccurateMath.pow(d, Long.MAX_VALUE - 1L), EXACT);
1435 }
1436 }
1437
1438 for (double d : DOUBLES) {
1439 if (Math.abs(d) > 1.0) {
1440 assertEquals(0.0, AccurateMath.pow(d, Long.MIN_VALUE + 1L), 0.0);
1441 }
1442 }
1443 for (double d : DOUBLES) {
1444 if (Math.abs(d) < 1.0) {
1445 assertEquals(0.0, AccurateMath.pow(d, Long.MAX_VALUE), 0.0);
1446 }
1447 }
1448
1449
1450
1451 for (long i : INTS) {
1452 if (i > 0L) {
1453 assertEquals(0.0, AccurateMath.pow(0.0, i), EXACT);
1454 }
1455 }
1456 for (long i : INTS) {
1457 if (i < 0L) {
1458 assertEquals(0.0, AccurateMath.pow(Double.POSITIVE_INFINITY, i), EXACT);
1459 }
1460 }
1461
1462
1463 for (long i : INTS) {
1464 if (i < 0L) {
1465 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(0.0, i), EXACT);
1466 }
1467 }
1468 for (long i : INTS) {
1469 if (i > 0L) {
1470 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(Double.POSITIVE_INFINITY, i), EXACT);
1471 }
1472 }
1473
1474
1475 for (long i : INTS) {
1476 if (i > 0L && (i & 1L) == 0L) {
1477 assertEquals(0.0, AccurateMath.pow(-0.0, i), EXACT);
1478 }
1479 }
1480 for (long i : INTS) {
1481 if (i < 0L && (i & 1L) == 0L) {
1482 assertEquals(0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
1483 }
1484 }
1485
1486
1487 for (long i : INTS) {
1488 if (i > 0L && (i & 1L) == 1L) {
1489 assertEquals(-0.0, AccurateMath.pow(-0.0, i), EXACT);
1490 }
1491 }
1492 for (long i : INTS) {
1493 if (i < 0L && (i & 1L) == 1L) {
1494 assertEquals(-0.0, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
1495 }
1496 }
1497
1498
1499 for (long i : INTS) {
1500 if (i > 0L && (i & 1L) == 0L) {
1501 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
1502 }
1503 }
1504 for (long i : INTS) {
1505 if (i < 0L && (i & 1L) == 0L) {
1506 assertEquals(Double.POSITIVE_INFINITY, AccurateMath.pow(-0.0, i), EXACT);
1507 }
1508 }
1509
1510
1511 for (long i : INTS) {
1512 if (i > 0L && (i & 1L) == 1L) {
1513 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.pow(Double.NEGATIVE_INFINITY, i), EXACT);
1514 }
1515 }
1516 for (long i : INTS) {
1517 if (i < 0L && (i & 1L) == 1L) {
1518 assertEquals(Double.NEGATIVE_INFINITY, AccurateMath.pow(-0.0, i), EXACT);
1519 }
1520 }
1521 for (double d : DOUBLES) {
1522
1523 if (d < 0.0 && Math.abs(d) <= Double.MAX_VALUE) {
1524 for (long i : INTS) {
1525
1526 if ((i & 1L) == 0L) {
1527 assertEquals(AccurateMath.pow(-d, i), AccurateMath.pow(d, i), EXACT);
1528 } else {
1529
1530 assertEquals(-AccurateMath.pow(-d, i), AccurateMath.pow(d, i), EXACT);
1531 }
1532
1533 }
1534 }
1535 }
1536
1537
1538 }
1539
1540 @Test
1541 public void testIncrementExactInt() {
1542 int[] specialValues = new int[] {
1543 Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
1544 Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
1545 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1546 -1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
1547 -1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
1548 };
1549 for (int a : specialValues) {
1550 BigInteger bdA = BigInteger.valueOf(a);
1551 BigInteger bdSum = bdA.add(BigInteger.ONE);
1552 if (bdSum.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
1553 bdSum.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
1554 try {
1555 AccurateMath.incrementExact(a);
1556 Assert.fail("an exception should have been thrown");
1557 } catch (ArithmeticException mae) {
1558
1559 }
1560 } else {
1561 assertEquals(bdSum, BigInteger.valueOf(AccurateMath.incrementExact(a)));
1562 }
1563 }
1564 }
1565
1566 @Test
1567 public void testDecrementExactInt() {
1568 int[] specialValues = new int[] {
1569 Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
1570 Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
1571 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1572 -1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
1573 -1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
1574 };
1575 for (int a : specialValues) {
1576 BigInteger bdA = BigInteger.valueOf(a);
1577 BigInteger bdSub = bdA.subtract(BigInteger.ONE);
1578 if (bdSub.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
1579 bdSub.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
1580 try {
1581 AccurateMath.decrementExact(a);
1582 fail("an exception should have been thrown");
1583 } catch (ArithmeticException mae) {
1584
1585 }
1586 } else {
1587 assertEquals(bdSub, BigInteger.valueOf(AccurateMath.decrementExact(a)));
1588 }
1589 }
1590 }
1591
1592 @Test
1593 public void testAddExactInt() {
1594 int[] specialValues = new int[] {
1595 Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
1596 Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
1597 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1598 -1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
1599 -1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
1600 };
1601 for (int a : specialValues) {
1602 for (int b : specialValues) {
1603 BigInteger bdA = BigInteger.valueOf(a);
1604 BigInteger bdB = BigInteger.valueOf(b);
1605 BigInteger bdSum = bdA.add(bdB);
1606 if (bdSum.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
1607 bdSum.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
1608 try {
1609 AccurateMath.addExact(a, b);
1610 fail("an exception should have been thrown");
1611 } catch (ArithmeticException mae) {
1612
1613 }
1614 } else {
1615 assertEquals(bdSum, BigInteger.valueOf(AccurateMath.addExact(a, b)));
1616 }
1617 }
1618 }
1619 }
1620
1621 @Test
1622 public void testAddExactLong() {
1623 long[] specialValues = new long[] {
1624 Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 2,
1625 Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 2,
1626 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1627 -1 - (Long.MIN_VALUE / 2), 0 - (Long.MIN_VALUE / 2), 1 - (Long.MIN_VALUE / 2),
1628 -1 + (Long.MAX_VALUE / 2), 0 + (Long.MAX_VALUE / 2), 1 + (Long.MAX_VALUE / 2),
1629 };
1630 for (long a : specialValues) {
1631 for (long b : specialValues) {
1632 BigInteger bdA = BigInteger.valueOf(a);
1633 BigInteger bdB = BigInteger.valueOf(b);
1634 BigInteger bdSum = bdA.add(bdB);
1635 if (bdSum.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0 ||
1636 bdSum.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
1637 try {
1638 AccurateMath.addExact(a, b);
1639 fail("an exception should have been thrown");
1640 } catch (ArithmeticException mae) {
1641
1642 }
1643 } else {
1644 assertEquals(bdSum, BigInteger.valueOf(AccurateMath.addExact(a, b)));
1645 }
1646 }
1647 }
1648 }
1649
1650 @Test
1651 public void testSubtractExactInt() {
1652 int[] specialValues = new int[] {
1653 Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
1654 Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
1655 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1656 -1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
1657 -1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
1658 };
1659 for (int a : specialValues) {
1660 for (int b : specialValues) {
1661 BigInteger bdA = BigInteger.valueOf(a);
1662 BigInteger bdB = BigInteger.valueOf(b);
1663 BigInteger bdSub = bdA.subtract(bdB);
1664 if (bdSub.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
1665 bdSub.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
1666 try {
1667 AccurateMath.subtractExact(a, b);
1668 fail("an exception should have been thrown");
1669 } catch (ArithmeticException mae) {
1670
1671 }
1672 } else {
1673 assertEquals(bdSub, BigInteger.valueOf(AccurateMath.subtractExact(a, b)));
1674 }
1675 }
1676 }
1677 }
1678
1679 @Test
1680 public void testSubtractExactLong() {
1681 long[] specialValues = new long[] {
1682 Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 2,
1683 Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 2,
1684 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1685 -1 - (Long.MIN_VALUE / 2), 0 - (Long.MIN_VALUE / 2), 1 - (Long.MIN_VALUE / 2),
1686 -1 + (Long.MAX_VALUE / 2), 0 + (Long.MAX_VALUE / 2), 1 + (Long.MAX_VALUE / 2),
1687 };
1688 for (long a : specialValues) {
1689 for (long b : specialValues) {
1690 BigInteger bdA = BigInteger.valueOf(a);
1691 BigInteger bdB = BigInteger.valueOf(b);
1692 BigInteger bdSub = bdA.subtract(bdB);
1693 if (bdSub.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0 ||
1694 bdSub.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
1695 try {
1696 AccurateMath.subtractExact(a, b);
1697 fail("an exception should have been thrown");
1698 } catch (ArithmeticException mae) {
1699
1700 }
1701 } else {
1702 assertEquals(bdSub, BigInteger.valueOf(AccurateMath.subtractExact(a, b)));
1703 }
1704 }
1705 }
1706 }
1707
1708 @Test
1709 public void testMultiplyExactInt() {
1710 int[] specialValues = new int[] {
1711 Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2,
1712 Integer.MAX_VALUE, Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 2,
1713 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1714 -1 - (Integer.MIN_VALUE / 2), 0 - (Integer.MIN_VALUE / 2), 1 - (Integer.MIN_VALUE / 2),
1715 -1 + (Integer.MAX_VALUE / 2), 0 + (Integer.MAX_VALUE / 2), 1 + (Integer.MAX_VALUE / 2),
1716 };
1717 for (int a : specialValues) {
1718 for (int b : specialValues) {
1719 BigInteger bdA = BigInteger.valueOf(a);
1720 BigInteger bdB = BigInteger.valueOf(b);
1721 BigInteger bdMul = bdA.multiply(bdB);
1722 if (bdMul.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 ||
1723 bdMul.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) {
1724 try {
1725 AccurateMath.multiplyExact(a, b);
1726 fail("an exception should have been thrown " + a + b);
1727 } catch (ArithmeticException mae) {
1728
1729 }
1730 } else {
1731 assertEquals(bdMul, BigInteger.valueOf(AccurateMath.multiplyExact(a, b)));
1732 }
1733 }
1734 }
1735 }
1736
1737 @Test
1738 public void testMultiplyExactLong() {
1739 long[] specialValues = new long[] {
1740 Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 2,
1741 Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 2,
1742 -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1743 -1 - (Long.MIN_VALUE / 2), 0 - (Long.MIN_VALUE / 2), 1 - (Long.MIN_VALUE / 2),
1744 -1 + (Long.MAX_VALUE / 2), 0 + (Long.MAX_VALUE / 2), 1 + (Long.MAX_VALUE / 2),
1745 };
1746 for (long a : specialValues) {
1747 for (long b : specialValues) {
1748 BigInteger bdA = BigInteger.valueOf(a);
1749 BigInteger bdB = BigInteger.valueOf(b);
1750 BigInteger bdMul = bdA.multiply(bdB);
1751 if (bdMul.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0 ||
1752 bdMul.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
1753 try {
1754 AccurateMath.multiplyExact(a, b);
1755 fail("an exception should have been thrown " + a + b);
1756 } catch (ArithmeticException mae) {
1757
1758 }
1759 } else {
1760 assertEquals(bdMul, BigInteger.valueOf(AccurateMath.multiplyExact(a, b)));
1761 }
1762 }
1763 }
1764 }
1765
1766 @Test(expected = ArithmeticException.class)
1767 public void testToIntExactTooLow() {
1768 AccurateMath.toIntExact(-1L + Integer.MIN_VALUE);
1769 }
1770
1771 @Test(expected = ArithmeticException.class)
1772 public void testToIntExactTooHigh() {
1773 AccurateMath.toIntExact(+1L + Integer.MAX_VALUE);
1774 }
1775
1776 @Test
1777 public void testToIntExact() {
1778 for (int n = -1000; n < 1000; ++n) {
1779 assertEquals(n, AccurateMath.toIntExact(0L + n));
1780 }
1781 assertEquals(Integer.MIN_VALUE, AccurateMath.toIntExact(0L + Integer.MIN_VALUE));
1782 assertEquals(Integer.MAX_VALUE, AccurateMath.toIntExact(0L + Integer.MAX_VALUE));
1783 }
1784
1785 @Test
1786 public void testFloorDivInt() {
1787 assertEquals(+1, AccurateMath.floorDiv(+4, +3));
1788 assertEquals(-2, AccurateMath.floorDiv(-4, +3));
1789 assertEquals(-2, AccurateMath.floorDiv(+4, -3));
1790 assertEquals(+1, AccurateMath.floorDiv(-4, -3));
1791 try {
1792 AccurateMath.floorDiv(1, 0);
1793 fail("an exception should have been thrown");
1794 } catch (ArithmeticException mae) {
1795
1796 }
1797 for (int a = -100; a <= 100; ++a) {
1798 for (int b = -100; b <= 100; ++b) {
1799 if (b != 0) {
1800 assertEquals(poorManFloorDiv(a, b), AccurateMath.floorDiv(a, b));
1801 }
1802 }
1803 }
1804 }
1805
1806 @Test
1807 public void testFloorModInt() {
1808 assertEquals(+1, AccurateMath.floorMod(+4, +3));
1809 assertEquals(+2, AccurateMath.floorMod(-4, +3));
1810 assertEquals(-2, AccurateMath.floorMod(+4, -3));
1811 assertEquals(-1, AccurateMath.floorMod(-4, -3));
1812 try {
1813 AccurateMath.floorMod(1, 0);
1814 fail("an exception should have been thrown");
1815 } catch (ArithmeticException mae) {
1816
1817 }
1818 for (int a = -100; a <= 100; ++a) {
1819 for (int b = -100; b <= 100; ++b) {
1820 if (b != 0) {
1821 assertEquals(poorManFloorMod(a, b), AccurateMath.floorMod(a, b));
1822 }
1823 }
1824 }
1825 }
1826
1827 @Test
1828 public void testFloorDivModInt() {
1829 UniformRandomProvider rng = RandomSource.WELL_1024_A.create(0x7ccab45edeaab90aL);
1830 for (int i = 0; i < 10000; ++i) {
1831 int a = rng.nextInt();
1832 int b = rng.nextInt();
1833 if (b == 0) {
1834 try {
1835 AccurateMath.floorDiv(a, b);
1836 fail("an exception should have been thrown");
1837 } catch (ArithmeticException mae) {
1838
1839 }
1840 } else {
1841 int d = AccurateMath.floorDiv(a, b);
1842 int m = AccurateMath.floorMod(a, b);
1843 assertEquals(AccurateMath.toIntExact(poorManFloorDiv(a, b)), d);
1844 assertEquals(AccurateMath.toIntExact(poorManFloorMod(a, b)), m);
1845 assertEquals(a, d * b + m);
1846 if (b < 0) {
1847 assertTrue(m <= 0);
1848 assertTrue(-m < -b);
1849 } else {
1850 assertTrue(m >= 0);
1851 assertTrue(m < b);
1852 }
1853 }
1854 }
1855 }
1856
1857 @Test
1858 public void testFloorDivLong() {
1859 assertEquals(+1L, AccurateMath.floorDiv(+4L, +3L));
1860 assertEquals(-2L, AccurateMath.floorDiv(-4L, +3L));
1861 assertEquals(-2L, AccurateMath.floorDiv(+4L, -3L));
1862 assertEquals(+1L, AccurateMath.floorDiv(-4L, -3L));
1863 try {
1864 AccurateMath.floorDiv(1L, 0L);
1865 fail("an exception should have been thrown");
1866 } catch (ArithmeticException mae) {
1867
1868 }
1869 for (long a = -100L; a <= 100L; ++a) {
1870 for (long b = -100L; b <= 100L; ++b) {
1871 if (b != 0) {
1872 assertEquals(poorManFloorDiv(a, b), AccurateMath.floorDiv(a, b));
1873 }
1874 }
1875 }
1876 }
1877
1878 @Test
1879 public void testFloorModLong() {
1880 assertEquals(+1L, AccurateMath.floorMod(+4L, +3L));
1881 assertEquals(+2L, AccurateMath.floorMod(-4L, +3L));
1882 assertEquals(-2L, AccurateMath.floorMod(+4L, -3L));
1883 assertEquals(-1L, AccurateMath.floorMod(-4L, -3L));
1884 try {
1885 AccurateMath.floorMod(1L, 0L);
1886 fail("an exception should have been thrown");
1887 } catch (ArithmeticException mae) {
1888
1889 }
1890 for (long a = -100L; a <= 100L; ++a) {
1891 for (long b = -100L; b <= 100L; ++b) {
1892 if (b != 0) {
1893 assertEquals(poorManFloorMod(a, b), AccurateMath.floorMod(a, b));
1894 }
1895 }
1896 }
1897 }
1898
1899 @Test
1900 public void testFloorDivModLong() {
1901 UniformRandomProvider rng = RandomSource.WELL_1024_A.create(0xb87b9bc14c96ccd5L);
1902 for (int i = 0; i < 10000; ++i) {
1903 long a = rng.nextLong();
1904 long b = rng.nextLong();
1905 if (b == 0) {
1906 try {
1907 AccurateMath.floorDiv(a, b);
1908 fail("an exception should have been thrown");
1909 } catch (ArithmeticException mae) {
1910
1911 }
1912 } else {
1913 long d = AccurateMath.floorDiv(a, b);
1914 long m = AccurateMath.floorMod(a, b);
1915 assertEquals(poorManFloorDiv(a, b), d);
1916 assertEquals(poorManFloorMod(a, b), m);
1917 assertEquals(a, d * b + m);
1918 if (b < 0) {
1919 assertTrue(m <= 0);
1920 assertTrue(-m < -b);
1921 } else {
1922 assertTrue(m >= 0);
1923 assertTrue(m < b);
1924 }
1925 }
1926 }
1927 }
1928
1929 private long poorManFloorDiv(long a, long b) {
1930
1931
1932 BigInteger q0 = BigInteger.valueOf(a / b);
1933 BigInteger r0 = BigInteger.valueOf(a % b);
1934 BigInteger fd = BigInteger.valueOf(Integer.MIN_VALUE);
1935 BigInteger bigB = BigInteger.valueOf(b);
1936
1937 for (int k = -2; k < 2; ++k) {
1938
1939 BigInteger bigK = BigInteger.valueOf(k);
1940 BigInteger q = q0.subtract(bigK);
1941 BigInteger r = r0.add(bigK.multiply(bigB));
1942 if (r.abs().compareTo(bigB.abs()) < 0 &&
1943 (r.longValue() == 0L || ((r.longValue() ^ b) & 0x8000000000000000L) == 0)) {
1944 if (fd.compareTo(q) < 0) {
1945 fd = q;
1946 }
1947 }
1948 }
1949
1950 return fd.longValue();
1951 }
1952
1953 private long poorManFloorMod(long a, long b) {
1954 return a - b * poorManFloorDiv(a, b);
1955 }
1956
1957
1958
1959
1960 @Test
1961 public void testRoundDown() {
1962 double x = 0x1.fffffffffffffp-2;
1963 assertTrue(x < 0.5d);
1964 assertEquals(0, AccurateMath.round(x));
1965
1966 x = 4503599627370497.0;
1967 assertEquals("4503599627370497", new BigDecimal(x).toString());
1968 assertEquals(x, Math.rint(x), 0.0);
1969 assertEquals(x, AccurateMath.round(x), 0.0);
1970
1971 }
1972 }