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 org.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.Test;
21  
22  /**
23   * Tests for {@link Precision.DoubleEquivalence} instances created with
24   * {@link Precision#doubleEquivalenceOfEpsilon(double)}.
25   */
26  class EpsilonDoubleEquivalenceTest {
27      @Test
28      void testInvalidEpsilonValues() {
29          // act/assert
30          Assertions.assertThrows(IllegalArgumentException.class, () -> Precision.doubleEquivalenceOfEpsilon(-1d));
31  
32          String msg;
33  
34          msg = Assertions.assertThrows(IllegalArgumentException.class,
35              () -> Precision.doubleEquivalenceOfEpsilon(Double.NaN)).getMessage();
36          Assertions.assertEquals("Invalid epsilon value: NaN", msg);
37  
38          msg = Assertions.assertThrows(IllegalArgumentException.class,
39              () -> Precision.doubleEquivalenceOfEpsilon(Double.POSITIVE_INFINITY)).getMessage();
40          Assertions.assertEquals("Invalid epsilon value: Infinity", msg);
41  
42          msg = Assertions.assertThrows(IllegalArgumentException.class,
43              () -> Precision.doubleEquivalenceOfEpsilon(Double.NEGATIVE_INFINITY)).getMessage();
44          Assertions.assertEquals("Invalid epsilon value: -Infinity", msg);
45      }
46  
47      @Test
48      void testSignum() {
49          // arrange
50          final double eps = 1e-2;
51  
52          final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(eps);
53  
54          // act/assert
55          Assertions.assertEquals(Double.POSITIVE_INFINITY, 1 / cmp.signum(0.0), 0d);
56          Assertions.assertEquals(Double.NEGATIVE_INFINITY, 1 / cmp.signum(-0.0), 0d);
57  
58          Assertions.assertEquals(Double.POSITIVE_INFINITY, 1 / cmp.signum(eps), 0d);
59          Assertions.assertEquals(Double.NEGATIVE_INFINITY, 1 / cmp.signum(-eps), 0d);
60  
61          Assertions.assertEquals(1, cmp.signum(Math.nextUp(eps)), 0d);
62          Assertions.assertEquals(-1, cmp.signum(Math.nextDown(-eps)), 0d);
63  
64          Assertions.assertTrue(Double.isNaN(cmp.signum(Double.NaN)));
65          Assertions.assertEquals(1, cmp.signum(Double.POSITIVE_INFINITY), 0d);
66          Assertions.assertEquals(-1, cmp.signum(Double.NEGATIVE_INFINITY), 0d);
67      }
68  
69      @Test
70      void testCompare_simple() {
71          // arrange
72          final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(1e-10);
73  
74          // act/assert
75          Assertions.assertEquals(0, cmp.compare(1, 1));
76          Assertions.assertEquals(-1, cmp.compare(1, 2));
77          Assertions.assertEquals(1, cmp.compare(2, 1));
78  
79          Assertions.assertEquals(0, cmp.compare(-1, -1));
80          Assertions.assertEquals(1, cmp.compare(-1, -2));
81          Assertions.assertEquals(-1, cmp.compare(-2, -1));
82      }
83  
84      @Test
85      void testCompare_compareToZero() {
86          // arrange
87          final double eps = 1e-2;
88  
89          final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(eps);
90  
91          // act/assert
92          Assertions.assertEquals(0, cmp.compare(0.0, 0.0));
93          Assertions.assertEquals(0, cmp.compare(+0.0, -0.0));
94          Assertions.assertEquals(0, cmp.compare(eps, -0.0));
95          Assertions.assertEquals(0, cmp.compare(+0.0, eps));
96  
97          Assertions.assertEquals(0, cmp.compare(-eps, -0.0));
98          Assertions.assertEquals(0, cmp.compare(+0.0, -eps));
99  
100         Assertions.assertEquals(-1, cmp.compare(0.0, 1.0));
101         Assertions.assertEquals(1, cmp.compare(1.0, 0.0));
102 
103         Assertions.assertEquals(1, cmp.compare(0.0, -1.0));
104         Assertions.assertEquals(-1, cmp.compare(-1.0, 0.0));
105     }
106 
107     @Test
108     void testCompare_compareNonZero() {
109         // arrange
110         final double eps = 1e-5;
111         final double small = 1e-3;
112         final double big = 1e100;
113 
114         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(eps);
115 
116         // act/assert
117         Assertions.assertEquals(0, cmp.compare(eps, 2 * eps));
118         Assertions.assertEquals(0, cmp.compare(-2 * eps, -eps));
119 
120         Assertions.assertEquals(0, cmp.compare(small, small + (0.9 * eps)));
121         Assertions.assertEquals(0, cmp.compare(-small - (0.9 * eps), -small));
122 
123         Assertions.assertEquals(0, cmp.compare(big, nextUp(big, 1)));
124         Assertions.assertEquals(0, cmp.compare(nextDown(-big, 1), -big));
125 
126         Assertions.assertEquals(-1, cmp.compare(small, small + (1.1 * eps)));
127         Assertions.assertEquals(1, cmp.compare(-small, -small - (1.1 * eps)));
128 
129         Assertions.assertEquals(-1, cmp.compare(big, nextUp(big, 2)));
130         Assertions.assertEquals(1, cmp.compare(-big, nextDown(-big, 2)));
131     }
132 
133     @Test
134     void testCompare_NaN() {
135         // arrange
136         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(1e-6);
137 
138         // act/assert
139         Assertions.assertEquals(-1, cmp.compare(0, Double.NaN));
140         Assertions.assertEquals(1, cmp.compare(Double.NaN, 0));
141         Assertions.assertEquals(0, cmp.compare(Double.NaN, Double.NaN));
142 
143         Assertions.assertEquals(-1, cmp.compare(Double.POSITIVE_INFINITY, Double.NaN));
144         Assertions.assertEquals(1, cmp.compare(Double.NaN, Double.POSITIVE_INFINITY));
145 
146         Assertions.assertEquals(-1, cmp.compare(Double.NEGATIVE_INFINITY, Double.NaN));
147         Assertions.assertEquals(1, cmp.compare(Double.NaN, Double.NEGATIVE_INFINITY));
148     }
149 
150     @Test
151     void testCompare_infinity() {
152         // arrange
153         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(1e-6);
154 
155         // act/assert
156         Assertions.assertEquals(-1, cmp.compare(0, Double.POSITIVE_INFINITY));
157         Assertions.assertEquals(1, cmp.compare(Double.POSITIVE_INFINITY, 0));
158         Assertions.assertEquals(0, cmp.compare(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
159 
160         Assertions.assertEquals(1, cmp.compare(0, Double.NEGATIVE_INFINITY));
161         Assertions.assertEquals(-1, cmp.compare(Double.NEGATIVE_INFINITY, 0));
162         Assertions.assertEquals(0, cmp.compare(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
163     }
164 
165     @Test
166     void testEq() {
167         // arrange
168         final double eps = Math.ulp(1.0);
169         final double twoEps = 2 * eps;
170         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(eps);
171 
172         // act/assert
173         Assertions.assertTrue(cmp.eq(0.0, 0.0));
174 
175         Assertions.assertTrue(cmp.eq(1.0, 1.0));
176         Assertions.assertTrue(cmp.eq(1.0, 1.0 + eps));
177         Assertions.assertTrue(cmp.eq(1.0, 1.0 - eps));
178         Assertions.assertFalse(cmp.eq(1.0, 1.0 + twoEps));
179         Assertions.assertFalse(cmp.eq(1.0, 1.0 - twoEps));
180 
181         Assertions.assertTrue(cmp.eq(-1.0, -1.0));
182         Assertions.assertTrue(cmp.eq(-1.0, -1.0 + eps));
183         Assertions.assertTrue(cmp.eq(-1.0, -1.0 - eps));
184         Assertions.assertFalse(cmp.eq(-1.0, -1.0 + twoEps));
185         Assertions.assertFalse(cmp.eq(-1.0, -1.0 - twoEps));
186     }
187 
188     @Test
189     void testEqZero() {
190         // arrange
191         final double eps = 1e-6;
192         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(eps);
193 
194         // act/assert
195         Assertions.assertTrue(cmp.eqZero(0.0));
196 
197         Assertions.assertFalse(cmp.eqZero(Math.nextUp(eps)));
198         Assertions.assertFalse(cmp.eqZero(Math.nextDown(-eps)));
199     }
200 
201     @Test
202     void testLt() {
203         // arrange
204         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(1e-6);
205 
206         // act/assert
207         Assertions.assertTrue(cmp.lt(1, 2));
208         Assertions.assertTrue(cmp.lt(-2, -1));
209 
210         Assertions.assertFalse(cmp.lt(1, 1));
211         Assertions.assertFalse(cmp.lt(-1, -1));
212         Assertions.assertFalse(cmp.lt(2, 1));
213         Assertions.assertFalse(cmp.lt(-1, -2));
214     }
215 
216     @Test
217     void testLte() {
218         // arrange
219         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(1e-6);
220 
221         // act/assert
222         Assertions.assertTrue(cmp.lte(1, 2));
223         Assertions.assertTrue(cmp.lte(-2, -1));
224         Assertions.assertTrue(cmp.lte(1, 1));
225         Assertions.assertTrue(cmp.lte(-1, -1));
226 
227         Assertions.assertFalse(cmp.lte(2, 1));
228         Assertions.assertFalse(cmp.lte(-1, -2));
229     }
230 
231     @Test
232     void testGt() {
233         // arrange
234         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(1e-6);
235 
236         // act/assert
237         Assertions.assertTrue(cmp.gt(2, 1));
238         Assertions.assertTrue(cmp.gt(-1, -2));
239 
240         Assertions.assertFalse(cmp.gt(1, 1));
241         Assertions.assertFalse(cmp.gt(-1, -1));
242         Assertions.assertFalse(cmp.gt(1, 2));
243         Assertions.assertFalse(cmp.gt(-2, -1));
244     }
245 
246     @Test
247     void testGte() {
248         // arrange
249         final Precision.DoubleEquivalence cmp = Precision.doubleEquivalenceOfEpsilon(1e-6);
250 
251         // act/assert
252         Assertions.assertTrue(cmp.gte(2, 1));
253         Assertions.assertTrue(cmp.gte(-1, -2));
254         Assertions.assertTrue(cmp.gte(1, 1));
255         Assertions.assertTrue(cmp.gte(-1, -1));
256 
257         Assertions.assertFalse(cmp.gte(1, 2));
258         Assertions.assertFalse(cmp.gte(-2, -1));
259     }
260 
261     /**
262      * Increments the given double value {@code count} number of times
263      * using {@link Math#nextUp(double)}.
264      * @param n
265      * @param count
266      * @return
267      */
268     private static double nextUp(final double n, final int count) {
269         double result = n;
270         for (int i = 0; i < count; ++i) {
271             result = Math.nextUp(result);
272         }
273 
274         return result;
275     }
276 
277     /**
278      * Decrements the given double value {@code count} number of times
279      * using {@link Math#nextDown(double)}.
280      * @param n
281      * @param count
282      * @return
283      */
284     private static double nextDown(final double n, final int count) {
285         double result = n;
286         for (int i = 0; i < count; ++i) {
287             result = Math.nextDown(result);
288         }
289 
290         return result;
291     }
292 }