View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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   * Test cases for the {@link Precision} class.
28   *
29   */
30  class PrecisionTest {
31  
32      // Interfaces to allow testing variants with the same conditions.
33      // All methods that should be tested using these interfaces as the
34      // symmetry is asserted.
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          * Compare two values.
106          *
107          * @param a First value
108          * @param b Second value
109          * @return 0 if the value are considered equal, -1 if the first is smaller than
110          * the second, 1 if the first is larger than the second.
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         // Use the version without the ulp argument
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             // This test is conditional
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             // Here: f == 5.304989477E-315;
268             // it is used to test the maximum ULP distance between two opposite sign numbers.
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             // Maximum distance between same sign numbers.
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     // Tests for floating point equality match the above tests with arguments
282     // converted to float
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         // Use the version without the ulp argument
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             // This test is conditional
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             // The 31-bit integer specification of the max positive ULP allows an extremely
385             // large range of a 23-bit mantissa and 8-bit exponent
386             Assertions.assertTrue(fun.equals(0, Float.MAX_VALUE, Integer.MAX_VALUE));
387             // Here: f == 2;
388             // it is used to test the maximum ULP distance between two opposite sign numbers.
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             // Maximum distance between same sign finite numbers is not possible as the upper
394             // limit is NaN. Check that it is not equal to anything.
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      * Assert sorting with the provided compare function.
431      *
432      * <p>The test makes assumptions on the input data using the compare function:
433      * <pre>
434      * v1 == v2; (v1,v2) < v3 < v4
435      * </pre>
436      *
437      * <p>The data will be supplemented with NaN and infinite values to ensure sorting is correct.
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                 // Check that order is consistent with the comparison function.
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         // NaN should be after all non-NaN numbers
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         // JIRA MATH-151
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         // BZ 35904
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             // expected
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         // MATH-151
602         Assertions.assertEquals(39.25, Precision.round(39.245, 2, RoundingMode.HALF_UP));
603 
604         // special values
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         // comparison of positive and negative zero is not possible -> always equal thus do string comparison
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         // Because they are adjacent floating point numbers, "a" and "b" are
645         // considered equal even though the allowed error is smaller than
646         // their difference.
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         // Because "a" and "c" are not adjacent, the tolerance is taken into
652         // account for assessing equality.
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         // Because they are adjacent floating point numbers, "a" and "b" are
666         // considered equal even though the allowed error is smaller than
667         // their difference.
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         // Because "a" and "c" are not adjacent, the tolerance is taken into
673         // account for assessing equality.
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         // a) 1 + EPSILON is equal to 1.
684         Assertions.assertEquals(1, 1 + Precision.EPSILON);
685 
686         // b) 1 + "the number after EPSILON" is not equal to 1.
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 }