1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.hipparchus.util;
15
16 import org.hipparchus.CalculusFieldElement;
17 import org.hipparchus.Field;
18 import org.hipparchus.FieldElement;
19 import org.hipparchus.exception.LocalizedCoreFormats;
20 import org.hipparchus.exception.MathIllegalArgumentException;
21 import org.hipparchus.exception.MathRuntimeException;
22 import org.hipparchus.exception.NullArgumentException;
23 import org.hipparchus.random.RandomDataGenerator;
24 import org.hipparchus.util.MathUtils.FieldSumAndResidual;
25 import org.hipparchus.util.MathUtils.SumAndResidual;
26 import org.junit.jupiter.api.Test;
27
28 import java.util.regex.Pattern;
29
30 import static org.junit.jupiter.api.Assertions.assertEquals;
31 import static org.junit.jupiter.api.Assertions.assertFalse;
32 import static org.junit.jupiter.api.Assertions.assertNotEquals;
33 import static org.junit.jupiter.api.Assertions.assertThrows;
34 import static org.junit.jupiter.api.Assertions.assertTrue;
35 import static org.junit.jupiter.api.Assertions.fail;
36
37
38
39
40 final class MathUtilsTest {
41 @Test
42 void testEqualsDouble() {
43 final double x = 1234.5678;
44 assertTrue(MathUtils.equals(x, x));
45 assertFalse(MathUtils.equals(x, -x));
46
47
48
49 assertTrue(MathUtils.equals(Double.NaN, Double.NaN));
50
51 final double mZero = -0d;
52 final double zero = 0d;
53 assertTrue(MathUtils.equals(zero, zero));
54 assertTrue(MathUtils.equals(mZero, mZero));
55 assertFalse(MathUtils.equals(mZero, zero));
56 }
57
58 @Test
59 void testHash() {
60 double[] testArray = {
61 Double.NaN,
62 Double.POSITIVE_INFINITY,
63 Double.NEGATIVE_INFINITY,
64 1d,
65 0d,
66 1E-14,
67 (1 + 1E-14),
68 Double.MIN_VALUE,
69 Double.MAX_VALUE };
70 for (int i = 0; i < testArray.length; i++) {
71 for (int j = 0; j < testArray.length; j++) {
72 if (i == j) {
73 assertEquals(MathUtils.hash(testArray[i]), MathUtils.hash(testArray[j]));
74 assertEquals(MathUtils.hash(testArray[j]), MathUtils.hash(testArray[i]));
75 } else {
76 assertTrue(MathUtils.hash(testArray[i]) != MathUtils.hash(testArray[j]));
77 assertTrue(MathUtils.hash(testArray[j]) != MathUtils.hash(testArray[i]));
78 }
79 }
80 }
81 }
82
83 @Test
84 void testArrayHash() {
85 assertEquals(0, MathUtils.hash(null));
86 assertEquals(MathUtils.hash(new double[] {
87 Double.NaN, Double.POSITIVE_INFINITY,
88 Double.NEGATIVE_INFINITY, 1d, 0d
89 }),
90 MathUtils.hash(new double[] {
91 Double.NaN, Double.POSITIVE_INFINITY,
92 Double.NEGATIVE_INFINITY, 1d, 0d
93 }));
94 assertNotEquals(MathUtils.hash(new double[]{1d}), MathUtils.hash(new double[]{FastMath.nextAfter(1d, 2d)}));
95 assertNotEquals(MathUtils.hash(new double[]{1d}), MathUtils.hash(new double[]{1d, 1d}));
96 }
97
98
99
100
101 @Test
102 void testPermutedArrayHash() {
103 double[] original = new double[10];
104 double[] permuted = new double[10];
105 RandomDataGenerator random = new RandomDataGenerator(100);
106
107
108 for (int i = 0; i < 10; i++) {
109 original[i] = random.nextUniform(i + 0.5, i + 0.75);
110 }
111
112
113 boolean isIdentity = true;
114 do {
115 int[] permutation = random.nextPermutation(10, 10);
116 for (int i = 0; i < 10; i++) {
117 if (i != permutation[i]) {
118 isIdentity = false;
119 }
120 permuted[i] = original[permutation[i]];
121 }
122 } while (isIdentity);
123
124
125 assertNotEquals(MathUtils.hash(original), MathUtils.hash(permuted));
126 }
127
128 @Test
129 void testIndicatorByte() {
130 assertEquals((byte)1, MathUtils.copySign((byte)1, (byte)2));
131 assertEquals((byte)1, MathUtils.copySign((byte)1, (byte)0));
132 assertEquals((byte)(-1), MathUtils.copySign((byte)1, (byte)(-2)));
133 }
134
135 @Test
136 void testIndicatorInt() {
137 assertEquals(1, MathUtils.copySign(1, 2));
138 assertEquals(1, MathUtils.copySign(1, 0));
139 assertEquals((-1), MathUtils.copySign(1, -2));
140 }
141
142 @Test
143 void testIndicatorLong() {
144 assertEquals(1L, MathUtils.copySign(1L, 2L));
145 assertEquals(1L, MathUtils.copySign(1L, 0L));
146 assertEquals(-1L, MathUtils.copySign(1L, -2L));
147 }
148
149 @Test
150 void testIndicatorShort() {
151 assertEquals((short)1, MathUtils.copySign((short)1, (short)2));
152 assertEquals((short)1, MathUtils.copySign((short)1, (short)0));
153 assertEquals((short)(-1), MathUtils.copySign((short)1, (short)(-2)));
154 }
155
156 @Test
157 void testNormalizeAngle() {
158 for (double a = -15.0; a <= 15.0; a += 0.1) {
159 for (double b = -15.0; b <= 15.0; b += 0.2) {
160 double c = MathUtils.normalizeAngle(a, b);
161 assertTrue((b - FastMath.PI) <= c);
162 assertTrue(c <= (b + FastMath.PI));
163 double twoK = FastMath.rint((a - c) / FastMath.PI);
164 assertEquals(c, a - twoK * FastMath.PI, 1.0e-14);
165 }
166 }
167 }
168
169 @Test
170 void testFieldNormalizeAngle() {
171 doTestFieldNormalizeAngle(Binary64Field.getInstance());
172 }
173
174 private <T extends CalculusFieldElement<T>> void doTestFieldNormalizeAngle(final Field<T> field) {
175 final T zero = field.getZero();
176 for (double a = -15.0; a <= 15.0; a += 0.1) {
177 for (double b = -15.0; b <= 15.0; b += 0.2) {
178 T c = MathUtils.normalizeAngle(zero.add(a), zero.add(b));
179 double cR = c.getReal();
180 assertTrue((b - FastMath.PI) <= cR);
181 assertTrue(cR <= (b + FastMath.PI));
182 double twoK = FastMath.rint((a - cR) / FastMath.PI);
183 assertEquals(cR, a - twoK * FastMath.PI, 1.0e-14);
184 }
185 }
186 }
187
188 @Test
189 void testReduce() {
190 final double period = -12.222;
191 final double offset = 13;
192
193 final double delta = 1.5;
194
195 double orig = offset + 122456789 * period + delta;
196 double expected = delta;
197 assertEquals(expected,
198 MathUtils.reduce(orig, period, offset),
199 1e-7);
200 assertEquals(expected,
201 MathUtils.reduce(orig, -period, offset),
202 1e-7);
203
204 orig = offset - 123356789 * period - delta;
205 expected = FastMath.abs(period) - delta;
206 assertEquals(expected,
207 MathUtils.reduce(orig, period, offset),
208 1e-6);
209 assertEquals(expected,
210 MathUtils.reduce(orig, -period, offset),
211 1e-6);
212
213 orig = offset - 123446789 * period + delta;
214 expected = delta;
215 assertEquals(expected,
216 MathUtils.reduce(orig, period, offset),
217 1e-6);
218 assertEquals(expected,
219 MathUtils.reduce(orig, -period, offset),
220 1e-6);
221
222 assertTrue(Double.isNaN(MathUtils.reduce(orig, Double.NaN, offset)));
223 assertTrue(Double.isNaN(MathUtils.reduce(Double.NaN, period, offset)));
224 assertTrue(Double.isNaN(MathUtils.reduce(orig, period, Double.NaN)));
225 assertTrue(Double.isNaN(MathUtils.reduce(orig, period,
226 Double.POSITIVE_INFINITY)));
227 assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
228 period, offset)));
229 assertTrue(Double.isNaN(MathUtils.reduce(orig,
230 Double.POSITIVE_INFINITY, offset)));
231 assertTrue(Double.isNaN(MathUtils.reduce(orig,
232 Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)));
233 assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
234 period, Double.POSITIVE_INFINITY)));
235 assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
236 Double.POSITIVE_INFINITY, offset)));
237 assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
238 Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)));
239 }
240
241 @Test
242 void testReduceComparedWithNormalizeAngle() {
243 final double tol = Math.ulp(1d);
244 final double period = 2 * Math.PI;
245 for (double a = -15; a <= 15; a += 0.5) {
246 for (double center = -15; center <= 15; center += 1) {
247 final double nA = MathUtils.normalizeAngle(a, center);
248 final double offset = center - Math.PI;
249 final double r = MathUtils.reduce(a, period, offset);
250 assertEquals(nA, r + offset, tol);
251 }
252 }
253 }
254
255 @Test
256 void testSignByte() {
257 final byte one = (byte) 1;
258 assertEquals((byte) 1, MathUtils.copySign(one, (byte) 2));
259 assertEquals((byte) (-1), MathUtils.copySign(one, (byte) (-2)));
260 }
261
262 @Test
263 void testSignInt() {
264 final int one = 1;
265 assertEquals(1, MathUtils.copySign(one, 2));
266 assertEquals((-1), MathUtils.copySign(one, -2));
267 }
268
269 @Test
270 void testSignLong() {
271 final long one = 1L;
272 assertEquals(1L, MathUtils.copySign(one, 2L));
273 assertEquals(-1L, MathUtils.copySign(one, -2L));
274 }
275
276 @Test
277 void testSignShort() {
278 final short one = (short) 1;
279 assertEquals((short) 1, MathUtils.copySign(one, (short) 2));
280 assertEquals((short) (-1), MathUtils.copySign(one, (short) (-2)));
281 }
282
283 @Test
284 void testCheckFinite() {
285 try {
286 MathUtils.checkFinite(Double.POSITIVE_INFINITY);
287 fail("an exception should have been thrown");
288 } catch (MathIllegalArgumentException e) {
289 assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
290 }
291 try {
292 MathUtils.checkFinite(Double.NEGATIVE_INFINITY);
293 fail("an exception should have been thrown");
294 } catch (MathIllegalArgumentException e) {
295 assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
296 }
297 try {
298 MathUtils.checkFinite(Double.NaN);
299 fail("an exception should have been thrown");
300 } catch (MathIllegalArgumentException e) {
301 assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
302 }
303
304 try {
305 MathUtils.checkFinite(new double[] {0, -1, Double.POSITIVE_INFINITY, -2, 3});
306 fail("an exception should have been thrown");
307 } catch (MathIllegalArgumentException e) {
308 assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
309 }
310 try {
311 MathUtils.checkFinite(new double[] {1, Double.NEGATIVE_INFINITY, -2, 3});
312 fail("an exception should have been thrown");
313 } catch (MathIllegalArgumentException e) {
314 assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
315 }
316 try {
317 MathUtils.checkFinite(new double[] {4, 3, -1, Double.NaN, -2, 1});
318 fail("an exception should have been thrown");
319 } catch (MathIllegalArgumentException e) {
320 assertEquals(LocalizedCoreFormats.NOT_FINITE_NUMBER, e.getSpecifier());
321 }
322 }
323
324 @Test
325 void testCheckNotNull1() {
326 try {
327 Object obj = null;
328 MathUtils.checkNotNull(obj);
329 } catch (NullArgumentException e) {
330
331 }
332 }
333
334 @Test
335 void testCheckNotNull2() {
336 try {
337 double[] array = null;
338 MathUtils.checkNotNull(array, LocalizedCoreFormats.INPUT_ARRAY);
339 } catch (NullArgumentException e) {
340
341 }
342 }
343
344 @Test
345 void testCopySignByte() {
346 byte a = MathUtils.copySign(Byte.MIN_VALUE, (byte) -1);
347 assertEquals(Byte.MIN_VALUE, a);
348
349 final byte minValuePlusOne = Byte.MIN_VALUE + (byte) 1;
350 a = MathUtils.copySign(minValuePlusOne, (byte) 1);
351 assertEquals(Byte.MAX_VALUE, a);
352
353 a = MathUtils.copySign(Byte.MAX_VALUE, (byte) -1);
354 assertEquals(minValuePlusOne, a);
355
356 final byte one = 1;
357 byte val = -2;
358 a = MathUtils.copySign(val, one);
359 assertEquals(-val, a);
360
361 final byte minusOne = -one;
362 val = 2;
363 a = MathUtils.copySign(val, minusOne);
364 assertEquals(-val, a);
365
366 val = 0;
367 a = MathUtils.copySign(val, minusOne);
368 assertEquals(val, a);
369
370 val = 0;
371 a = MathUtils.copySign(val, one);
372 assertEquals(val, a);
373 }
374
375 @Test
376 void testCopySignByte2() {
377 assertThrows(MathRuntimeException.class, () -> MathUtils.copySign(Byte.MIN_VALUE, (byte) 1));
378 }
379
380 @Test
381 public void testHipparchusVersion() {
382 final Pattern pattern = Pattern.compile("unknown|[0-9.]*(?:-SNAPSHOT)?");
383 assertTrue(pattern.matcher(MathUtils.getHipparchusVersion()).matches());
384 }
385
386
387
388
389 @Test
390 void testTwoSum() {
391
392
393 final double a1 = 0.1;
394 final double b1 = 0.2;
395 final SumAndResidual result1 = MathUtils.twoSum(a1, b1);
396 assertEquals(a1 + b1, result1.getSum(), 0.);
397 assertEquals(a1 + b1, result1.getSum() + result1.getResidual(), 0.);
398 assertNotEquals(0., result1.getResidual(), 0.);
399
400
401
402 final double a2 = -615.7212034581913;
403 final double b2 = -964.5993814837093;
404 final SumAndResidual result2 = MathUtils.twoSum(a2, b2);
405 assertEquals(a2 + b2, result2.getSum(), 0.);
406 assertEquals(a2 + b2, result2.getSum() + result2.getResidual(), 0.);
407 assertNotEquals(0., result2.getResidual(), 0.);
408
409
410
411 final double a3 = 60.348375484313706;
412 final double b3 = 191.5142071130258;
413 final SumAndResidual result3 = MathUtils.twoSum(a3, b3);
414 assertEquals(a3 + b3, result3.getSum(), 0.);
415 assertEquals(a3 + b3, result3.getSum() + result3.getResidual(), 0.);
416 assertNotEquals(0., result3.getResidual(), 0.);
417
418
419
420 final double a4 = 622.8314146170453;
421 final double b4 = 0.0004877004669900762;
422 final SumAndResidual result4 = MathUtils.twoSum(a4, b4);
423 assertEquals(a4 + b4, result4.getSum(), 0.);
424 assertEquals(a4 + b4, result4.getSum() + result4.getResidual(), 0.);
425 assertNotEquals(0., result4.getResidual(), 0.);
426 }
427
428
429
430
431 @Test
432 void testTwoSumField() {
433 final Tuple a = new Tuple(0.1, -615.7212034581913, 60.348375484313706, 622.8314146170453);
434 final Tuple b = new Tuple(0.2, -964.5993814837093, 191.5142071130258, 0.0004877004669900762);
435 final FieldSumAndResidual<Tuple> result = MathUtils.twoSum(a, b);
436 for (int i = 0; i < a.getDimension(); ++i) {
437 assertEquals(a.getComponent(i) + b.getComponent(i), result.getSum().getComponent(i), 0.);
438 assertEquals(a.getComponent(i) + b.getComponent(i),
439 result.getSum().getComponent(i) + result.getResidual().getComponent(i), 0.);
440 assertNotEquals(0., result.getResidual().getComponent(i), 0.);
441 }
442 }
443
444 }