1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.numbers.core;
18
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.math.RoundingMode;
22
23 import org.junit.jupiter.api.Assertions;
24 import org.junit.jupiter.api.Test;
25
26
27
28
29
30 class PrecisionTest {
31
32
33
34
35
36 @FunctionalInterface
37 private interface Equals {
38 default boolean equals(double a, double b) {
39 final boolean r = equalsImp(a, b);
40 Assertions.assertEquals(r, equalsImp(b, a),
41 () -> String.format("equals(%s, %s) != equals(%s, %s)", a, b, b, a));
42 return r;
43 }
44 boolean equalsImp(double a, double b);
45 }
46
47 @FunctionalInterface
48 private interface EqualsWithDelta {
49 default boolean equals(double a, double b, double delta) {
50 final boolean r = equalsImp(a, b, delta);
51 Assertions.assertEquals(r, equalsImp(b, a, delta),
52 () -> String.format("equals(%s, %s, %s) != equals(%s, %s, %s)", a, b, delta, b, a, delta));
53 return r;
54 }
55 boolean equalsImp(double a, double b, double delta);
56 }
57
58 @FunctionalInterface
59 private interface EqualsWithUlps {
60 default boolean equals(double a, double b, int ulps) {
61 final boolean r = equalsImp(a, b, ulps);
62 Assertions.assertEquals(r, equalsImp(b, a, ulps),
63 () -> String.format("equals(%s, %s, %d) != equals(%s, %s, %d)", a, b, ulps, b, a, ulps));
64 return r;
65 }
66 boolean equalsImp(double a, double b, int ulps);
67 }
68
69 @FunctionalInterface
70 private interface FloatEquals {
71 default boolean equals(float a, float b) {
72 final boolean r = equalsImp(a, b);
73 Assertions.assertEquals(r, equalsImp(b, a),
74 () -> String.format("equals(%s, %s) != equals(%s, %s)", a, b, b, a));
75 return r;
76 }
77 boolean equalsImp(float a, float b);
78 }
79
80 @FunctionalInterface
81 private interface FloatEqualsWithDelta {
82 default boolean equals(float a, float b, float delta) {
83 final boolean r = equalsImp(a, b, delta);
84 Assertions.assertEquals(r, equalsImp(b, a, delta),
85 () -> String.format("equals(%s, %s, %s) != equals(%s, %s, %s)", a, b, delta, b, a, delta));
86 return r;
87 }
88 boolean equalsImp(float a, float b, float delta);
89 }
90
91 @FunctionalInterface
92 private interface FloatEqualsWithUlps {
93 default boolean equals(float a, float b, int ulps) {
94 final boolean r = equalsImp(a, b, ulps);
95 Assertions.assertEquals(r, equalsImp(b, a, ulps),
96 () -> String.format("equals(%s, %s, %d) != equals(%s, %s, %d)", a, b, ulps, b, a, ulps));
97 return r;
98 }
99 boolean equalsImp(float a, float b, int ulps);
100 }
101
102 @FunctionalInterface
103 private interface CompareFunction {
104
105
106
107
108
109
110
111
112 int compare(double a, double b);
113 }
114
115 @FunctionalInterface
116 private interface CompareToWithDelta {
117 default int compareTo(double a, double b, double delta) {
118 final int r = compareToImp(a, b, delta);
119 Assertions.assertEquals(r, -compareToImp(b, a, delta),
120 () -> String.format("compareTo(%s, %s, %s) != -compareTo(%s, %s, %s)", a, b, delta, b, a, delta));
121 return r;
122 }
123 int compareToImp(double a, double b, double delta);
124 }
125
126 @FunctionalInterface
127 private interface CompareToWithUlps {
128 default int compareTo(double a, double b, int ulps) {
129 final int r = compareToImp(a, b, ulps);
130 Assertions.assertEquals(r, -compareToImp(b, a, ulps),
131 () -> String.format("compareTo(%s, %s, %d) != -compareTo(%s, %s, %d)", a, b, ulps, b, a, ulps));
132 return r;
133 }
134 int compareToImp(double a, double b, int ulps);
135 }
136
137 @Test
138 void testEqualsWithRelativeTolerance() {
139 final EqualsWithDelta fun = Precision::equalsWithRelativeTolerance;
140
141 Assertions.assertTrue(fun.equals(0d, 0d, 0d));
142 Assertions.assertTrue(fun.equals(0d, 1 / Double.NEGATIVE_INFINITY, 0d));
143
144 final double eps = 1e-14;
145 Assertions.assertFalse(fun.equals(1.987654687654968, 1.987654687654988, eps));
146 Assertions.assertTrue(fun.equals(1.987654687654968, 1.987654687654987, eps));
147 Assertions.assertFalse(fun.equals(1.987654687654968, 1.987654687654948, eps));
148 Assertions.assertTrue(fun.equals(1.987654687654968, 1.987654687654949, eps));
149
150 Assertions.assertFalse(fun.equals(Precision.SAFE_MIN, 0.0, eps));
151
152 Assertions.assertFalse(fun.equals(1.0000000000001e-300, 1e-300, eps));
153 Assertions.assertTrue(fun.equals(1.00000000000001e-300, 1e-300, eps));
154
155 Assertions.assertFalse(fun.equals(Double.NEGATIVE_INFINITY, 1.23, eps));
156 Assertions.assertFalse(fun.equals(Double.POSITIVE_INFINITY, 1.23, eps));
157
158 Assertions.assertTrue(fun.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, eps));
159 Assertions.assertTrue(fun.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, eps));
160 Assertions.assertFalse(fun.equals(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, eps));
161
162 Assertions.assertFalse(fun.equals(Double.NaN, 1.23, eps));
163 Assertions.assertFalse(fun.equals(Double.NaN, Double.NaN, eps));
164 }
165
166 @Test
167 void testEqualsIncludingNaN() {
168 final Equals fun = Precision::equalsIncludingNaN;
169
170 double[] testArray = {
171 Double.NaN,
172 Double.POSITIVE_INFINITY,
173 Double.NEGATIVE_INFINITY,
174 1d,
175 0d };
176 for (int i = 0; i < testArray.length; i++) {
177 for (int j = 0; j < testArray.length; j++) {
178 if (i == j) {
179 Assertions.assertTrue(fun.equals(testArray[i], testArray[j]));
180 Assertions.assertTrue(fun.equals(testArray[j], testArray[i]));
181 } else {
182 Assertions.assertFalse(fun.equals(testArray[i], testArray[j]));
183 Assertions.assertFalse(fun.equals(testArray[j], testArray[i]));
184 }
185 }
186 }
187 }
188
189 @Test
190 void testEqualsWithAllowedDelta() {
191 assertEqualsWithAllowedDelta(Precision::equals, false);
192 }
193
194 @Test
195 void testEqualsIncludingNaNWithAllowedDelta() {
196 assertEqualsWithAllowedDelta(Precision::equalsIncludingNaN, true);
197 }
198
199 private static void assertEqualsWithAllowedDelta(EqualsWithDelta fun, boolean nanAreEqual) {
200 Assertions.assertTrue(fun.equals(153.0000, 153.0000, .0625));
201 Assertions.assertTrue(fun.equals(153.0000, 153.0625, .0625));
202 Assertions.assertTrue(fun.equals(152.9375, 153.0000, .0625));
203 Assertions.assertFalse(fun.equals(153.0000, 153.0625, .0624));
204 Assertions.assertFalse(fun.equals(152.9374, 153.0000, .0625));
205 Assertions.assertEquals(nanAreEqual, fun.equals(Double.NaN, Double.NaN, 1.0));
206 Assertions.assertTrue(fun.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0));
207 Assertions.assertTrue(fun.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 1.0));
208 Assertions.assertFalse(fun.equals(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0));
209 }
210
211 @Test
212 void testEqualsWithAllowedUlps() {
213 assertEqualsWithAllowedUlps(Precision::equals, false, false);
214 }
215
216 @Test
217 void testEqualsWithImplicitAllowedUlpsOf1() {
218
219 assertEqualsWithAllowedUlps((a, b, ulp) -> Precision.equals(a, b), false, true);
220 }
221
222 @Test
223 void testEqualsIncludingNaNWithAllowedUlps() {
224 assertEqualsWithAllowedUlps(Precision::equalsIncludingNaN, true, false);
225 }
226
227 private static void assertEqualsWithAllowedUlps(EqualsWithUlps fun,
228 boolean nanAreEqual, boolean fixed1Ulp) {
229 Assertions.assertTrue(fun.equals(0.0, -0.0, 1));
230 Assertions.assertTrue(fun.equals(Double.MIN_VALUE, -0.0, 1));
231 Assertions.assertFalse(fun.equals(Double.MIN_VALUE, -Double.MIN_VALUE, 1));
232
233 Assertions.assertTrue(fun.equals(1.0, 1 + Math.ulp(1d), 1));
234 Assertions.assertFalse(fun.equals(1.0, 1 + 2 * Math.ulp(1d), 1));
235
236 for (double value : new double[] {153.0, -128.0, 0.0, 1.0}) {
237 Assertions.assertTrue(fun.equals(value, value, 1));
238 Assertions.assertTrue(fun.equals(value, Math.nextUp(value), 1));
239 Assertions.assertFalse(fun.equals(value, Math.nextUp(Math.nextUp(value)), 1));
240 Assertions.assertTrue(fun.equals(value, Math.nextDown(value), 1));
241 Assertions.assertFalse(fun.equals(value, Math.nextDown(Math.nextDown(value)), 1));
242
243 if (!fixed1Ulp) {
244 Assertions.assertFalse(fun.equals(value, value, -1), "Negative ULP should be supported");
245 Assertions.assertFalse(fun.equals(value, Math.nextUp(value), 0));
246 Assertions.assertTrue(fun.equals(value, Math.nextUp(Math.nextUp(value)), 2));
247 Assertions.assertTrue(fun.equals(value, Math.nextDown(Math.nextDown(value)), 2));
248 }
249 }
250
251 Assertions.assertTrue(fun.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 1));
252 Assertions.assertTrue(fun.equals(Double.MAX_VALUE, Double.POSITIVE_INFINITY, 1));
253
254 Assertions.assertTrue(fun.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 1));
255 Assertions.assertTrue(fun.equals(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY, 1));
256
257 Assertions.assertEquals(nanAreEqual, fun.equals(Double.NaN, Double.NaN, 1));
258 Assertions.assertEquals(nanAreEqual, fun.equals(Double.NaN, Double.NaN, 0));
259 Assertions.assertFalse(fun.equals(Double.NaN, 0, 0));
260 Assertions.assertFalse(fun.equals(0, Double.NaN, 0));
261 Assertions.assertFalse(fun.equals(Double.NaN, Double.POSITIVE_INFINITY, 0));
262 Assertions.assertFalse(fun.equals(Double.NaN, Double.NEGATIVE_INFINITY, 0));
263
264 if (!fixed1Ulp) {
265 Assertions.assertFalse(fun.equals(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Integer.MAX_VALUE));
266 Assertions.assertFalse(fun.equals(0, Double.MAX_VALUE, Integer.MAX_VALUE));
267
268
269 final double f = Double.longBitsToDouble(1L << 30);
270 Assertions.assertFalse(fun.equals(-f, f, Integer.MAX_VALUE));
271 Assertions.assertTrue(fun.equals(-f, Math.nextDown(f), Integer.MAX_VALUE));
272 Assertions.assertTrue(fun.equals(Math.nextUp(-f), f, Integer.MAX_VALUE));
273
274 final double f2 = Double.longBitsToDouble((1L << 30) + Integer.MAX_VALUE);
275 Assertions.assertTrue(fun.equals(f, f2, Integer.MAX_VALUE));
276 Assertions.assertFalse(fun.equals(f, Math.nextUp(f2), Integer.MAX_VALUE));
277 Assertions.assertFalse(fun.equals(Math.nextDown(f), f2, Integer.MAX_VALUE));
278 }
279 }
280
281
282
283
284 @Test
285 void testFloatEqualsIncludingNaN() {
286 final FloatEquals fun = Precision::equalsIncludingNaN;
287
288 float[] testArray = {
289 Float.NaN,
290 Float.POSITIVE_INFINITY,
291 Float.NEGATIVE_INFINITY,
292 1f,
293 0f };
294 for (int i = 0; i < testArray.length; i++) {
295 for (int j = 0; j < testArray.length; j++) {
296 if (i == j) {
297 Assertions.assertTrue(fun.equals(testArray[i], testArray[j]));
298 Assertions.assertTrue(fun.equals(testArray[j], testArray[i]));
299 } else {
300 Assertions.assertFalse(fun.equals(testArray[i], testArray[j]));
301 Assertions.assertFalse(fun.equals(testArray[j], testArray[i]));
302 }
303 }
304 }
305 }
306
307 @Test
308 void testFloatEqualsWithAllowedDelta() {
309 assertFloatEqualsWithAllowedDelta(Precision::equals, false);
310 }
311
312 @Test
313 void testFloatEqualsIncludingNaNWithAllowedDelta() {
314 assertFloatEqualsWithAllowedDelta(Precision::equalsIncludingNaN, true);
315 }
316
317 private static void assertFloatEqualsWithAllowedDelta(FloatEqualsWithDelta fun, boolean nanAreEqual) {
318 Assertions.assertTrue(fun.equals(153.0000f, 153.0000f, .0625f));
319 Assertions.assertTrue(fun.equals(153.0000f, 153.0625f, .0625f));
320 Assertions.assertTrue(fun.equals(152.9375f, 153.0000f, .0625f));
321 Assertions.assertFalse(fun.equals(153.0000f, 153.0625f, .0624f));
322 Assertions.assertFalse(fun.equals(152.9374f, 153.0000f, .0625f));
323 Assertions.assertEquals(nanAreEqual, fun.equals(Float.NaN, Float.NaN, 1.0f));
324 Assertions.assertTrue(fun.equals(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, 1.0f));
325 Assertions.assertTrue(fun.equals(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, 1.0f));
326 Assertions.assertFalse(fun.equals(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, 1.0f));
327 }
328
329 @Test
330 void testFloatEqualsWithAllowedUlps() {
331 assertFloatEqualsWithAllowedUlps(Precision::equals, false, false);
332 }
333
334 @Test
335 void testFloatEqualsWithImplicitAllowedUlpsOf1() {
336
337 assertFloatEqualsWithAllowedUlps((a, b, ulp) -> Precision.equals(a, b), false, true);
338 }
339
340 @Test
341 void testFloatEqualsIncludingNaNWithAllowedUlps() {
342 assertFloatEqualsWithAllowedUlps(Precision::equalsIncludingNaN, true, false);
343 }
344
345 private static void assertFloatEqualsWithAllowedUlps(FloatEqualsWithUlps fun,
346 boolean nanAreEqual, boolean fixed1Ulp) {
347 Assertions.assertTrue(fun.equals(0.0f, -0.0f, 1));
348 Assertions.assertTrue(fun.equals(Float.MIN_VALUE, -0.0f, 1));
349 Assertions.assertFalse(fun.equals(Float.MIN_VALUE, -Float.MIN_VALUE, 1));
350
351 Assertions.assertTrue(fun.equals(1.0f, 1f + Math.ulp(1f), 1));
352 Assertions.assertFalse(fun.equals(1.0f, 1f + 2 * Math.ulp(1f), 1));
353
354 for (float value : new float[] {153.0f, -128.0f, 0.0f, 1.0f}) {
355 Assertions.assertTrue(fun.equals(value, value, 1));
356 Assertions.assertTrue(fun.equals(value, Math.nextUp(value), 1));
357 Assertions.assertFalse(fun.equals(value, Math.nextUp(Math.nextUp(value)), 1));
358 Assertions.assertTrue(fun.equals(value, Math.nextDown(value), 1));
359 Assertions.assertFalse(fun.equals(value, Math.nextDown(Math.nextDown(value)), 1));
360
361 if (!fixed1Ulp) {
362 Assertions.assertFalse(fun.equals(value, value, -1), "Negative ULP should be supported");
363 Assertions.assertFalse(fun.equals(value, Math.nextUp(value), 0));
364 Assertions.assertTrue(fun.equals(value, Math.nextUp(Math.nextUp(value)), 2));
365 Assertions.assertTrue(fun.equals(value, Math.nextDown(Math.nextDown(value)), 2));
366 }
367 }
368
369 Assertions.assertTrue(fun.equals(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, 1));
370 Assertions.assertTrue(fun.equals(Float.MAX_VALUE, Float.POSITIVE_INFINITY, 1));
371
372 Assertions.assertTrue(fun.equals(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, 1));
373 Assertions.assertTrue(fun.equals(-Float.MAX_VALUE, Float.NEGATIVE_INFINITY, 1));
374
375 Assertions.assertEquals(nanAreEqual, fun.equals(Float.NaN, Float.NaN, 1));
376 Assertions.assertEquals(nanAreEqual, fun.equals(Float.NaN, Float.NaN, 0));
377 Assertions.assertFalse(fun.equals(Float.NaN, 0, 0));
378 Assertions.assertFalse(fun.equals(0, Float.NaN, 0));
379 Assertions.assertFalse(fun.equals(Float.NaN, Float.POSITIVE_INFINITY, 0));
380 Assertions.assertFalse(fun.equals(Float.NaN, Float.NEGATIVE_INFINITY, 0));
381
382 if (!fixed1Ulp) {
383 Assertions.assertFalse(fun.equals(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Integer.MAX_VALUE));
384
385
386 Assertions.assertTrue(fun.equals(0, Float.MAX_VALUE, Integer.MAX_VALUE));
387
388
389 final float f = Float.intBitsToFloat(1 << 30);
390 Assertions.assertFalse(fun.equals(-f, f, Integer.MAX_VALUE));
391 Assertions.assertTrue(fun.equals(-f, Math.nextDown(f), Integer.MAX_VALUE));
392 Assertions.assertTrue(fun.equals(Math.nextUp(-f), f, Integer.MAX_VALUE));
393
394
395 final float f2 = Float.intBitsToFloat(Integer.MAX_VALUE);
396 Assertions.assertEquals(Double.NaN, f2);
397 Assertions.assertFalse(fun.equals(f2, Float.MAX_VALUE, Integer.MAX_VALUE));
398 Assertions.assertFalse(fun.equals(f2, 0, Integer.MAX_VALUE));
399 }
400 }
401
402 @Test
403 void testCompareToEpsilon() {
404 Assertions.assertEquals(0, Precision.compareTo(152.33, 152.32, .011));
405 Assertions.assertTrue(Precision.compareTo(152.308, 152.32, .011) < 0);
406 Assertions.assertTrue(Precision.compareTo(152.33, 152.318, .011) > 0);
407 Assertions.assertEquals(0, Precision.compareTo(Double.MIN_VALUE, +0.0, Double.MIN_VALUE));
408 Assertions.assertEquals(0, Precision.compareTo(Double.MIN_VALUE, -0.0, Double.MIN_VALUE));
409 }
410
411 @Test
412 void testSortWithCompareTo() {
413 final double eps = 0.1;
414 final double v1 = 0.02;
415 final double v2 = v1 + 0.5 * eps;
416 final CompareToWithDelta fun = Precision::compareTo;
417 assertSortWithCompareTo((a, b) -> fun.compareTo(a, b, eps), v1, v2, 13, 42);
418 }
419
420 @Test
421 void testSortWithCompareToMaxUlps() {
422 final int ulps = 1000;
423 final double v1 = 0.02;
424 final double v2 = v1 + 0.5 * ulps * Math.ulp(v1);
425 final CompareToWithUlps fun = Precision::compareTo;
426 assertSortWithCompareTo((a, b) -> fun.compareTo(a, b, ulps), v1, v2, 0.75, 2.23);
427 }
428
429
430
431
432
433
434
435
436
437
438
439 private static void assertSortWithCompareTo(CompareFunction compare,
440 double v1, double v2, double v3, double v4) {
441 Assertions.assertEquals(0, compare.compare(v1, v2));
442 Assertions.assertEquals(-1, compare.compare(v1, v3));
443 Assertions.assertEquals(-1, compare.compare(v2, v3));
444 Assertions.assertEquals(-1, compare.compare(v3, v4));
445 final Double[] array = {Double.NaN, v1, v2, Double.NaN, v3, v4, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY};
446 for (int i = 0; i < 10; i++) {
447 Collections.shuffle(Arrays.asList(array));
448 Arrays.sort(array, compare::compare);
449
450 for (int j = 0; j < array.length - 1; j++) {
451 final int c = compare.compare(array[j],
452 array[j + 1]);
453
454 Assertions.assertNotEquals(1, c);
455 }
456 Assertions.assertEquals(Double.NEGATIVE_INFINITY, array[0]);
457 Assertions.assertTrue(array[1] == v1 || array[1] == v2);
458 Assertions.assertTrue(array[2] == v1 || array[2] == v2);
459 Assertions.assertEquals(v3, array[3]);
460 Assertions.assertEquals(v4, array[4]);
461 Assertions.assertEquals(Double.POSITIVE_INFINITY, array[5]);
462 Assertions.assertEquals(Double.NaN, array[6]);
463 Assertions.assertEquals(Double.NaN, array[7]);
464 }
465 }
466
467 @Test
468 void testCompareToMaxUlps() {
469 final CompareToWithUlps fun = Precision::compareTo;
470
471 double a = 152.32;
472 double delta = Math.ulp(a);
473 for (int i = 0; i <= 10; ++i) {
474 if (i <= 5) {
475 Assertions.assertEquals(+0, fun.compareTo(a, a + i * delta, 5));
476 Assertions.assertEquals(+0, fun.compareTo(a, a - i * delta, 5));
477 } else {
478 Assertions.assertEquals(-1, fun.compareTo(a, a + i * delta, 5));
479 Assertions.assertEquals(+1, fun.compareTo(a, a - i * delta, 5));
480 }
481 }
482
483 Assertions.assertEquals(+0, fun.compareTo(-0.0, 0.0, 0));
484
485 Assertions.assertEquals(-1, fun.compareTo(-Double.MIN_VALUE, -0.0, 0));
486 Assertions.assertEquals(+0, fun.compareTo(-Double.MIN_VALUE, -0.0, 1));
487 Assertions.assertEquals(-1, fun.compareTo(-Double.MIN_VALUE, +0.0, 0));
488 Assertions.assertEquals(+0, fun.compareTo(-Double.MIN_VALUE, +0.0, 1));
489
490 Assertions.assertEquals(+1, fun.compareTo(+Double.MIN_VALUE, -0.0, 0));
491 Assertions.assertEquals(+0, fun.compareTo(+Double.MIN_VALUE, -0.0, 1));
492 Assertions.assertEquals(+1, fun.compareTo(+Double.MIN_VALUE, +0.0, 0));
493 Assertions.assertEquals(+0, fun.compareTo(+Double.MIN_VALUE, +0.0, 1));
494
495 Assertions.assertEquals(-1, fun.compareTo(-Double.MIN_VALUE, Double.MIN_VALUE, 0));
496 Assertions.assertEquals(-1, fun.compareTo(-Double.MIN_VALUE, Double.MIN_VALUE, 1));
497 Assertions.assertEquals(+0, fun.compareTo(-Double.MIN_VALUE, Double.MIN_VALUE, 2));
498
499 Assertions.assertEquals(+0, fun.compareTo(Double.MAX_VALUE, Double.POSITIVE_INFINITY, 1));
500 Assertions.assertEquals(-1, fun.compareTo(Double.MAX_VALUE, Double.POSITIVE_INFINITY, 0));
501
502
503 Assertions.assertEquals(+1, fun.compareTo(Double.NaN, Double.MAX_VALUE, Integer.MAX_VALUE));
504 Assertions.assertEquals(+1, fun.compareTo(Double.NaN, Double.POSITIVE_INFINITY, Integer.MAX_VALUE));
505 Assertions.assertEquals(+1, fun.compareTo(Double.NaN, 42, Integer.MAX_VALUE));
506 Assertions.assertEquals(0, fun.compareTo(Double.NaN, Double.NaN, Integer.MAX_VALUE));
507 }
508
509 @Test
510 void testRoundDouble() {
511 double x = 1.234567890;
512 Assertions.assertEquals(1.23, Precision.round(x, 2));
513 Assertions.assertEquals(1.235, Precision.round(x, 3));
514 Assertions.assertEquals(1.2346, Precision.round(x, 4));
515
516
517 Assertions.assertEquals(39.25, Precision.round(39.245, 2));
518 Assertions.assertEquals(39.24, Precision.round(39.245, 2, RoundingMode.DOWN));
519 double xx = 39.0;
520 xx += 245d / 1000d;
521 Assertions.assertEquals(39.25, Precision.round(xx, 2));
522
523
524 Assertions.assertEquals(30.1d, Precision.round(30.095d, 2));
525 Assertions.assertEquals(30.1d, Precision.round(30.095d, 1));
526 Assertions.assertEquals(33.1d, Precision.round(33.095d, 1));
527 Assertions.assertEquals(33.1d, Precision.round(33.095d, 2));
528 Assertions.assertEquals(50.09d, Precision.round(50.085d, 2));
529 Assertions.assertEquals(50.19d, Precision.round(50.185d, 2));
530 Assertions.assertEquals(50.01d, Precision.round(50.005d, 2));
531 Assertions.assertEquals(30.01d, Precision.round(30.005d, 2));
532 Assertions.assertEquals(30.65d, Precision.round(30.645d, 2));
533
534 Assertions.assertEquals(1.24, Precision.round(x, 2, RoundingMode.CEILING));
535 Assertions.assertEquals(1.235, Precision.round(x, 3, RoundingMode.CEILING));
536 Assertions.assertEquals(1.2346, Precision.round(x, 4, RoundingMode.CEILING));
537 Assertions.assertEquals(-1.23, Precision.round(-x, 2, RoundingMode.CEILING));
538 Assertions.assertEquals(-1.234, Precision.round(-x, 3, RoundingMode.CEILING));
539 Assertions.assertEquals(-1.2345, Precision.round(-x, 4, RoundingMode.CEILING));
540
541 Assertions.assertEquals(1.23, Precision.round(x, 2, RoundingMode.DOWN));
542 Assertions.assertEquals(1.234, Precision.round(x, 3, RoundingMode.DOWN));
543 Assertions.assertEquals(1.2345, Precision.round(x, 4, RoundingMode.DOWN));
544 Assertions.assertEquals(-1.23, Precision.round(-x, 2, RoundingMode.DOWN));
545 Assertions.assertEquals(-1.234, Precision.round(-x, 3, RoundingMode.DOWN));
546 Assertions.assertEquals(-1.2345, Precision.round(-x, 4, RoundingMode.DOWN));
547
548 Assertions.assertEquals(1.23, Precision.round(x, 2, RoundingMode.FLOOR));
549 Assertions.assertEquals(1.234, Precision.round(x, 3, RoundingMode.FLOOR));
550 Assertions.assertEquals(1.2345, Precision.round(x, 4, RoundingMode.FLOOR));
551 Assertions.assertEquals(-1.24, Precision.round(-x, 2, RoundingMode.FLOOR));
552 Assertions.assertEquals(-1.235, Precision.round(-x, 3, RoundingMode.FLOOR));
553 Assertions.assertEquals(-1.2346, Precision.round(-x, 4, RoundingMode.FLOOR));
554
555 Assertions.assertEquals(1.23, Precision.round(x, 2, RoundingMode.HALF_DOWN));
556 Assertions.assertEquals(1.235, Precision.round(x, 3, RoundingMode.HALF_DOWN));
557 Assertions.assertEquals(1.2346, Precision.round(x, 4, RoundingMode.HALF_DOWN));
558 Assertions.assertEquals(-1.23, Precision.round(-x, 2, RoundingMode.HALF_DOWN));
559 Assertions.assertEquals(-1.235, Precision.round(-x, 3, RoundingMode.HALF_DOWN));
560 Assertions.assertEquals(-1.2346, Precision.round(-x, 4, RoundingMode.HALF_DOWN));
561 Assertions.assertEquals(1.234, Precision.round(1.2345, 3, RoundingMode.HALF_DOWN));
562 Assertions.assertEquals(-1.234, Precision.round(-1.2345, 3, RoundingMode.HALF_DOWN));
563
564 Assertions.assertEquals(1.23, Precision.round(x, 2, RoundingMode.HALF_EVEN));
565 Assertions.assertEquals(1.235, Precision.round(x, 3, RoundingMode.HALF_EVEN));
566 Assertions.assertEquals(1.2346, Precision.round(x, 4, RoundingMode.HALF_EVEN));
567 Assertions.assertEquals(-1.23, Precision.round(-x, 2, RoundingMode.HALF_EVEN));
568 Assertions.assertEquals(-1.235, Precision.round(-x, 3, RoundingMode.HALF_EVEN));
569 Assertions.assertEquals(-1.2346, Precision.round(-x, 4, RoundingMode.HALF_EVEN));
570 Assertions.assertEquals(1.234, Precision.round(1.2345, 3, RoundingMode.HALF_EVEN));
571 Assertions.assertEquals(-1.234, Precision.round(-1.2345, 3, RoundingMode.HALF_EVEN));
572 Assertions.assertEquals(1.236, Precision.round(1.2355, 3, RoundingMode.HALF_EVEN));
573 Assertions.assertEquals(-1.236, Precision.round(-1.2355, 3, RoundingMode.HALF_EVEN));
574
575 Assertions.assertEquals(1.23, Precision.round(x, 2, RoundingMode.HALF_UP));
576 Assertions.assertEquals(1.235, Precision.round(x, 3, RoundingMode.HALF_UP));
577 Assertions.assertEquals(1.2346, Precision.round(x, 4, RoundingMode.HALF_UP));
578 Assertions.assertEquals(-1.23, Precision.round(-x, 2, RoundingMode.HALF_UP));
579 Assertions.assertEquals(-1.235, Precision.round(-x, 3, RoundingMode.HALF_UP));
580 Assertions.assertEquals(-1.2346, Precision.round(-x, 4, RoundingMode.HALF_UP));
581 Assertions.assertEquals(1.235, Precision.round(1.2345, 3, RoundingMode.HALF_UP));
582 Assertions.assertEquals(-1.235, Precision.round(-1.2345, 3, RoundingMode.HALF_UP));
583
584 Assertions.assertEquals(-1.23, Precision.round(-1.23, 2, RoundingMode.UNNECESSARY));
585 Assertions.assertEquals(1.23, Precision.round(1.23, 2, RoundingMode.UNNECESSARY));
586
587 try {
588 Precision.round(1.234, 2, RoundingMode.UNNECESSARY);
589 Assertions.fail();
590 } catch (ArithmeticException ex) {
591
592 }
593
594 Assertions.assertEquals(1.24, Precision.round(x, 2, RoundingMode.UP));
595 Assertions.assertEquals(1.235, Precision.round(x, 3, RoundingMode.UP));
596 Assertions.assertEquals(1.2346, Precision.round(x, 4, RoundingMode.UP));
597 Assertions.assertEquals(-1.24, Precision.round(-x, 2, RoundingMode.UP));
598 Assertions.assertEquals(-1.235, Precision.round(-x, 3, RoundingMode.UP));
599 Assertions.assertEquals(-1.2346, Precision.round(-x, 4, RoundingMode.UP));
600
601
602 Assertions.assertEquals(39.25, Precision.round(39.245, 2, RoundingMode.HALF_UP));
603
604
605 Assertions.assertEquals(Double.NaN, Precision.round(Double.NaN, 2));
606 Assertions.assertEquals(0.0, Precision.round(0.0, 2));
607 Assertions.assertEquals(Double.POSITIVE_INFINITY, Precision.round(Double.POSITIVE_INFINITY, 2));
608 Assertions.assertEquals(Double.NEGATIVE_INFINITY, Precision.round(Double.NEGATIVE_INFINITY, 2));
609
610 Assertions.assertEquals("-0.0", Double.toString(Precision.round(-0.0, 0)));
611 Assertions.assertEquals("-0.0", Double.toString(Precision.round(-1e-10, 0)));
612 }
613
614 @Test
615 void testRepresentableDelta() {
616 int nonRepresentableCount = 0;
617 final double x = 100;
618 final int numTrials = 10000;
619 for (int i = 0; i < numTrials; i++) {
620 final double originalDelta = Math.random();
621 final double delta = Precision.representableDelta(x, originalDelta);
622 if (delta != originalDelta) {
623 ++nonRepresentableCount;
624 }
625 }
626
627 Assertions.assertTrue(nonRepresentableCount / (double) numTrials > 0.9);
628 }
629
630 @Test
631 void testIssue721() {
632 Assertions.assertEquals(-53, Math.getExponent(Precision.EPSILON));
633 Assertions.assertEquals(-1022, Math.getExponent(Precision.SAFE_MIN));
634 }
635
636 @Test
637 void testMath475() {
638 final EqualsWithDelta fun = Precision::equals;
639
640 final double a = 1.7976931348623182E16;
641 final double b = Math.nextUp(a);
642
643 double diff = Math.abs(a - b);
644
645
646
647 Assertions.assertTrue(fun.equals(a, b, 0.5 * diff));
648
649 final double c = Math.nextUp(b);
650 diff = Math.abs(a - c);
651
652
653 Assertions.assertTrue(fun.equals(a, c, diff));
654 Assertions.assertFalse(fun.equals(a, c, Math.nextDown(1.0) * diff));
655 }
656
657 @Test
658 void testMath475Float() {
659 final FloatEqualsWithDelta fun = Precision::equals;
660
661 final float a = 1.7976931348623182E16f;
662 final float b = Math.nextUp(a);
663
664 float diff = Math.abs(a - b);
665
666
667
668 Assertions.assertTrue(fun.equals(a, b, 0.5f * diff));
669
670 final float c = Math.nextUp(b);
671 diff = Math.abs(a - c);
672
673
674 Assertions.assertTrue(fun.equals(a, c, diff));
675 Assertions.assertFalse(fun.equals(a, c, Math.nextDown(1.0f) * diff));
676 }
677
678 @Test
679 void testMath843() {
680 final double afterEpsilon = Math.nextAfter(Precision.EPSILON,
681 Double.POSITIVE_INFINITY);
682
683
684 Assertions.assertEquals(1, 1 + Precision.EPSILON);
685
686
687 Assertions.assertNotEquals(1, 1 + afterEpsilon, 0.0);
688 }
689
690 @Test
691 void testMath1127() {
692 final EqualsWithUlps fun = Precision::equals;
693 Assertions.assertFalse(fun.equals(2.0, -2.0, 1));
694 Assertions.assertTrue(fun.equals(0.0, -0.0, 0));
695 final FloatEqualsWithUlps fun2 = Precision::equals;
696 Assertions.assertFalse(fun2.equals(2.0f, -2.0f, 1));
697 Assertions.assertTrue(fun2.equals(0.0f, -0.0f, 0));
698 }
699 }