1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.core.precision;
18
19 import org.apache.commons.geometry.core.GeometryTestUtils;
20 import org.junit.Assert;
21 import org.junit.Test;
22
23 public class EpsilonDoublePrecisionContextTest {
24
25 @Test
26 public void testGetters() {
27
28 final double eps = 1e-6;
29
30
31 final EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
32
33
34 Assert.assertEquals(eps, ctx.getEpsilon(), 0.0);
35 Assert.assertEquals(eps, ctx.getMaxZero(), 0.0);
36 }
37
38 @Test
39 public void testInvalidEpsilonValues() {
40
41 GeometryTestUtils.assertThrows(() -> {
42 new EpsilonDoublePrecisionContext(-1.0);
43 }, IllegalArgumentException.class);
44
45 GeometryTestUtils.assertThrows(() -> {
46 new EpsilonDoublePrecisionContext(Double.NaN);
47 }, IllegalArgumentException.class, "Invalid epsilon value: NaN");
48
49 GeometryTestUtils.assertThrows(() -> {
50 new EpsilonDoublePrecisionContext(Double.POSITIVE_INFINITY);
51 }, IllegalArgumentException.class, "Invalid epsilon value: Infinity");
52
53 GeometryTestUtils.assertThrows(() -> {
54 new EpsilonDoublePrecisionContext(Double.NEGATIVE_INFINITY);
55 }, IllegalArgumentException.class, "Invalid epsilon value: -Infinity");
56 }
57
58 @Test
59 public void testSign() {
60
61 final double eps = 1e-2;
62
63 final EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
64
65
66 Assert.assertEquals(0, ctx.sign(0.0));
67 Assert.assertEquals(0, ctx.sign(-0.0));
68
69 Assert.assertEquals(0, ctx.sign(1e-2));
70 Assert.assertEquals(0, ctx.sign(-1e-2));
71
72 Assert.assertEquals(1, ctx.sign(1e-1));
73 Assert.assertEquals(-1, ctx.sign(-1e-1));
74
75 Assert.assertEquals(1, ctx.sign(Double.NaN));
76 Assert.assertEquals(1, ctx.sign(Double.POSITIVE_INFINITY));
77 Assert.assertEquals(-1, ctx.sign(Double.NEGATIVE_INFINITY));
78 }
79
80 @Test
81 public void testCompare_compareToZero() {
82
83 final double eps = 1e-2;
84
85 final EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
86
87
88 Assert.assertEquals(0, ctx.compare(0.0, 0.0));
89 Assert.assertEquals(0, ctx.compare(+0.0, -0.0));
90 Assert.assertEquals(0, ctx.compare(eps, -0.0));
91 Assert.assertEquals(0, ctx.compare(+0.0, eps));
92
93 Assert.assertEquals(0, ctx.compare(-eps, -0.0));
94 Assert.assertEquals(0, ctx.compare(+0.0, -eps));
95
96 Assert.assertEquals(-1, ctx.compare(0.0, 1.0));
97 Assert.assertEquals(1, ctx.compare(1.0, 0.0));
98
99 Assert.assertEquals(1, ctx.compare(0.0, -1.0));
100 Assert.assertEquals(-1, ctx.compare(-1.0, 0.0));
101 }
102
103 @Test
104 public void testCompare_compareNonZero() {
105
106 final double eps = 1e-5;
107 final double small = 1e-3;
108 final double big = 1e100;
109
110 final EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
111
112
113 Assert.assertEquals(0, ctx.compare(eps, 2 * eps));
114 Assert.assertEquals(0, ctx.compare(-2 * eps, -eps));
115
116 Assert.assertEquals(0, ctx.compare(small, small + (0.9 * eps)));
117 Assert.assertEquals(0, ctx.compare(-small - (0.9 * eps), -small));
118
119 Assert.assertEquals(0, ctx.compare(big, nextUp(big, 1)));
120 Assert.assertEquals(0, ctx.compare(nextDown(-big, 1), -big));
121
122 Assert.assertEquals(-1, ctx.compare(small, small + (1.1 * eps)));
123 Assert.assertEquals(1, ctx.compare(-small, -small - (1.1 * eps)));
124
125 Assert.assertEquals(-1, ctx.compare(big, nextUp(big, 2)));
126 Assert.assertEquals(1, ctx.compare(-big, nextDown(-big, 2)));
127 }
128
129 @Test
130 public void testCompare_NaN() {
131
132 final EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(1e-6);
133
134
135 Assert.assertEquals(1, ctx.compare(0, Double.NaN));
136 Assert.assertEquals(1, ctx.compare(Double.NaN, 0));
137 Assert.assertEquals(1, ctx.compare(Double.NaN, Double.NaN));
138
139 Assert.assertEquals(1, ctx.compare(Double.POSITIVE_INFINITY, Double.NaN));
140 Assert.assertEquals(1, ctx.compare(Double.NaN, Double.POSITIVE_INFINITY));
141
142 Assert.assertEquals(1, ctx.compare(Double.NEGATIVE_INFINITY, Double.NaN));
143 Assert.assertEquals(1, ctx.compare(Double.NaN, Double.NEGATIVE_INFINITY));
144 }
145
146 @Test
147 public void testCompare_infinity() {
148
149 final EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(1e-6);
150
151
152 Assert.assertEquals(-1, ctx.compare(0, Double.POSITIVE_INFINITY));
153 Assert.assertEquals(1, ctx.compare(Double.POSITIVE_INFINITY, 0));
154 Assert.assertEquals(0, ctx.compare(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
155
156 Assert.assertEquals(1, ctx.compare(0, Double.NEGATIVE_INFINITY));
157 Assert.assertEquals(-1, ctx.compare(Double.NEGATIVE_INFINITY, 0));
158 Assert.assertEquals(0, ctx.compare(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
159 }
160
161 @Test
162 public void testGetMaxZero_isZeroEqualityThreshold() {
163
164 final double eps = 1e-2;
165
166 final EpsilonDoublePrecisionContext ctx = new EpsilonDoublePrecisionContext(eps);
167
168 final double maxZero = ctx.getMaxZero();
169
170
171 Assert.assertTrue(ctx.eqZero(maxZero));
172 Assert.assertTrue(ctx.eqZero(nextDown(maxZero, 1)));
173 Assert.assertFalse(ctx.eqZero(nextUp(maxZero, 1)));
174
175 Assert.assertTrue(ctx.eqZero(-maxZero));
176 Assert.assertTrue(ctx.eqZero(nextUp(-maxZero, 1)));
177 Assert.assertFalse(ctx.eqZero(nextDown(-maxZero, 1)));
178 }
179
180 @Test
181 public void testHashCode() {
182
183 final EpsilonDoublePrecisionContext a = new EpsilonDoublePrecisionContext(1e-6);
184 final EpsilonDoublePrecisionContext b = new EpsilonDoublePrecisionContext(1e-7);
185 final EpsilonDoublePrecisionContext c = new EpsilonDoublePrecisionContext(1e-6);
186
187
188 Assert.assertEquals(a.hashCode(), a.hashCode());
189 Assert.assertEquals(a.hashCode(), c.hashCode());
190
191 Assert.assertNotEquals(a.hashCode(), b.hashCode());
192 }
193
194 @Test
195 public void testEquals() {
196
197 final EpsilonDoublePrecisionContext a = new EpsilonDoublePrecisionContext(1e-6);
198 final EpsilonDoublePrecisionContext b = new EpsilonDoublePrecisionContext(1e-7);
199 final EpsilonDoublePrecisionContext c = new EpsilonDoublePrecisionContext(1e-6);
200
201
202 Assert.assertFalse(a.equals(null));
203 Assert.assertFalse(a.equals(new Object()));
204 Assert.assertNotEquals(a, b);
205 Assert.assertNotEquals(b, a);
206
207 Assert.assertEquals(a, a);
208 Assert.assertEquals(a, c);
209 }
210
211 @Test
212 public void testEqualsAndHashCode_signedZeroConsistency() {
213
214 final EpsilonDoublePrecisionContext a = new EpsilonDoublePrecisionContext(0.0);
215 final EpsilonDoublePrecisionContext b = new EpsilonDoublePrecisionContext(-0.0);
216 final EpsilonDoublePrecisionContext c = new EpsilonDoublePrecisionContext(0.0);
217 final EpsilonDoublePrecisionContext d = new EpsilonDoublePrecisionContext(-0.0);
218
219
220 Assert.assertFalse(a.equals(b));
221 Assert.assertNotEquals(a.hashCode(), b.hashCode());
222
223 Assert.assertTrue(a.equals(c));
224 Assert.assertEquals(a.hashCode(), c.hashCode());
225
226 Assert.assertTrue(b.equals(d));
227 Assert.assertEquals(b.hashCode(), d.hashCode());
228 }
229
230 @Test
231 public void testToString() {
232
233 final EpsilonDoublePrecisionContext a = new EpsilonDoublePrecisionContext(1d);
234
235
236 final String str = a.toString();
237
238
239 Assert.assertTrue(str.contains("EpsilonDoublePrecisionContext"));
240 Assert.assertTrue(str.contains("epsilon= 1"));
241 }
242
243
244
245
246
247
248
249
250 private static double nextUp(final double n, final int count) {
251 double result = n;
252 for (int i = 0; i < count; ++i) {
253 result = Math.nextUp(result);
254 }
255
256 return result;
257 }
258
259
260
261
262
263
264
265
266 private static double nextDown(final double n, final int count) {
267 double result = n;
268 for (int i = 0; i < count; ++i) {
269 result = Math.nextDown(result);
270 }
271
272 return result;
273 }
274 }