1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with this
4    * work for additional information regarding copyright ownership. The ASF
5    * licenses this file to You under the Apache License, Version 2.0 (the
6    * "License"); you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
9    * or agreed to in writing, software distributed under the License is
10   * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11   * KIND, either express or implied. See the License for the specific language
12   * governing permissions and limitations under the License.
13   */
14  package org.apache.commons.math.util;
15  
16  import java.math.BigDecimal;
17  import java.math.BigInteger;
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import junit.framework.Test;
24  import junit.framework.TestCase;
25  import junit.framework.TestSuite;
26  
27  import org.apache.commons.math.random.RandomDataImpl;
28  import org.apache.commons.math.TestUtils;
29  
30  /**
31   * Test cases for the MathUtils class.
32   * @version $Revision: 790243 $ $Date: 2007-08-16 15:36:33 -0500 (Thu, 16 Aug
33   *          2007) $
34   */
35  public final class MathUtilsTest extends TestCase {
36  
37      public MathUtilsTest(String name) {
38          super(name);
39      }
40  
41      public static Test suite() {
42          TestSuite suite = new TestSuite(MathUtilsTest.class);
43          suite.setName("MathUtils Tests");
44          return suite;
45      }
46  
47      /** cached binomial coefficients */
48      private static final List<Map<Integer, Long>> binomialCache = new ArrayList<Map<Integer, Long>>();
49  
50      /**
51       * Exact (caching) recursive implementation to test against
52       */
53      private long binomialCoefficient(int n, int k) throws ArithmeticException {
54          if (binomialCache.size() > n) {
55              Long cachedResult = binomialCache.get(n).get(Integer.valueOf(k));
56              if (cachedResult != null) {
57                  return cachedResult.longValue();
58              }
59          }
60          long result = -1;
61          if ((n == k) || (k == 0)) {
62              result = 1;
63          } else if ((k == 1) || (k == n - 1)) {
64              result = n;
65          } else {
66              // Reduce stack depth for larger values of n
67              if (k < n - 100) {
68                  binomialCoefficient(n - 100, k);
69              }
70              if (k > 100) {
71                  binomialCoefficient(n - 100, k - 100);
72              }
73              result = MathUtils.addAndCheck(binomialCoefficient(n - 1, k - 1),
74                  binomialCoefficient(n - 1, k));
75          }
76          if (result == -1) {
77              throw new ArithmeticException(
78                  "error computing binomial coefficient");
79          }
80          for (int i = binomialCache.size(); i < n + 1; i++) {
81              binomialCache.add(new HashMap<Integer, Long>());
82          }
83          binomialCache.get(n).put(Integer.valueOf(k), Long.valueOf(result));
84          return result;
85      }
86  
87      /**
88       * Exact direct multiplication implementation to test against
89       */
90      private long factorial(int n) {
91          long result = 1;
92          for (int i = 2; i <= n; i++) {
93              result *= i;
94          }
95          return result;
96      }
97  
98      /** Verify that b(0,0) = 1 */
99      public void test0Choose0() {
100         assertEquals(MathUtils.binomialCoefficientDouble(0, 0), 1d, 0);
101         assertEquals(MathUtils.binomialCoefficientLog(0, 0), 0d, 0);
102         assertEquals(MathUtils.binomialCoefficient(0, 0), 1);
103     }
104 
105     public void testAddAndCheck() {
106         int big = Integer.MAX_VALUE;
107         int bigNeg = Integer.MIN_VALUE;
108         assertEquals(big, MathUtils.addAndCheck(big, 0));
109         try {
110             MathUtils.addAndCheck(big, 1);
111             fail("Expecting ArithmeticException");
112         } catch (ArithmeticException ex) {
113         }
114         try {
115             MathUtils.addAndCheck(bigNeg, -1);
116             fail("Expecting ArithmeticException");
117         } catch (ArithmeticException ex) {
118         }
119     }
120 
121     public void testAddAndCheckLong() {
122         long max = Long.MAX_VALUE;
123         long min = Long.MIN_VALUE;
124         assertEquals(max, MathUtils.addAndCheck(max, 0L));
125         assertEquals(min, MathUtils.addAndCheck(min, 0L));
126         assertEquals(max, MathUtils.addAndCheck(0L, max));
127         assertEquals(min, MathUtils.addAndCheck(0L, min));
128         assertEquals(1, MathUtils.addAndCheck(-1L, 2L));
129         assertEquals(1, MathUtils.addAndCheck(2L, -1L));
130         assertEquals(-3, MathUtils.addAndCheck(-2L, -1L));
131         assertEquals(min, MathUtils.addAndCheck(min + 1, -1L));
132         testAddAndCheckLongFailure(max, 1L);
133         testAddAndCheckLongFailure(min, -1L);
134         testAddAndCheckLongFailure(1L, max);
135         testAddAndCheckLongFailure(-1L, min);
136     }
137 
138     private void testAddAndCheckLongFailure(long a, long b) {
139         try {
140             MathUtils.addAndCheck(a, b);
141             fail("Expecting ArithmeticException");
142         } catch (ArithmeticException ex) {
143             // success
144         }
145     }
146 
147     public void testBinomialCoefficient() {
148         long[] bcoef5 = {
149             1,
150             5,
151             10,
152             10,
153             5,
154             1 };
155         long[] bcoef6 = {
156             1,
157             6,
158             15,
159             20,
160             15,
161             6,
162             1 };
163         for (int i = 0; i < 6; i++) {
164             assertEquals("5 choose " + i, bcoef5[i], MathUtils.binomialCoefficient(5, i));
165         }
166         for (int i = 0; i < 7; i++) {
167             assertEquals("6 choose " + i, bcoef6[i], MathUtils.binomialCoefficient(6, i));
168         }
169 
170         for (int n = 1; n < 10; n++) {
171             for (int k = 0; k <= n; k++) {
172                 assertEquals(n + " choose " + k, binomialCoefficient(n, k), MathUtils.binomialCoefficient(n, k));
173                 assertEquals(n + " choose " + k, binomialCoefficient(n, k), MathUtils.binomialCoefficientDouble(n, k), Double.MIN_VALUE);
174                 assertEquals(n + " choose " + k, Math.log(binomialCoefficient(n, k)), MathUtils.binomialCoefficientLog(n, k), 10E-12);
175             }
176         }
177 
178         int[] n = { 34, 66, 100, 1500, 1500 };
179         int[] k = { 17, 33, 10, 1500 - 4, 4 };
180         for (int i = 0; i < n.length; i++) {
181             long expected = binomialCoefficient(n[i], k[i]);
182             assertEquals(n[i] + " choose " + k[i], expected,
183                 MathUtils.binomialCoefficient(n[i], k[i]));
184             assertEquals(n[i] + " choose " + k[i], expected,
185                 MathUtils.binomialCoefficientDouble(n[i], k[i]), 0.0);
186             assertEquals("log(" + n[i] + " choose " + k[i] + ")", Math.log(expected),
187                 MathUtils.binomialCoefficientLog(n[i], k[i]), 0.0);
188         }
189     }
190 
191     /**
192      * Tests correctness for large n and sharpness of upper bound in API doc
193      * JIRA: MATH-241
194      */
195     public void testBinomialCoefficientLarge() throws Exception {
196         // This tests all legal and illegal values for n <= 200.
197         for (int n = 0; n <= 200; n++) {
198             for (int k = 0; k <= n; k++) {
199                 long ourResult = -1;
200                 long exactResult = -1;
201                 boolean shouldThrow = false;
202                 boolean didThrow = false;
203                 try {
204                     ourResult = MathUtils.binomialCoefficient(n, k);
205                 } catch (ArithmeticException ex) {
206                     didThrow = true;
207                 }
208                 try {
209                     exactResult = binomialCoefficient(n, k);
210                 } catch (ArithmeticException ex) {
211                     shouldThrow = true;
212                 }
213                 assertEquals(n + " choose " + k, exactResult, ourResult);
214                 assertEquals(n + " choose " + k, shouldThrow, didThrow);
215                 assertTrue(n + " choose " + k, (n > 66 || !didThrow));
216 
217                 if (!shouldThrow && exactResult > 1) {
218                     assertEquals(n + " choose " + k, 1.,
219                         MathUtils.binomialCoefficientDouble(n, k) / exactResult, 1e-10);
220                     assertEquals(n + " choose " + k, 1,
221                         MathUtils.binomialCoefficientLog(n, k) / Math.log(exactResult), 1e-10);
222                 }
223             }
224         }
225 
226         long ourResult = MathUtils.binomialCoefficient(300, 3);
227         long exactResult = binomialCoefficient(300, 3);
228         assertEquals(exactResult, ourResult);
229 
230         ourResult = MathUtils.binomialCoefficient(700, 697);
231         exactResult = binomialCoefficient(700, 697);
232         assertEquals(exactResult, ourResult);
233 
234         // This one should throw
235         try {
236             MathUtils.binomialCoefficient(700, 300);
237             fail("Expecting ArithmeticException");
238         } catch (ArithmeticException ex) {
239             // Expected
240         }
241 
242         int n = 10000;
243         ourResult = MathUtils.binomialCoefficient(n, 3);
244         exactResult = binomialCoefficient(n, 3);
245         assertEquals(exactResult, ourResult);
246         assertEquals(1, MathUtils.binomialCoefficientDouble(n, 3) / exactResult, 1e-10);
247         assertEquals(1, MathUtils.binomialCoefficientLog(n, 3) / Math.log(exactResult), 1e-10);
248 
249     }
250 
251     public void testBinomialCoefficientFail() {
252         try {
253             MathUtils.binomialCoefficient(4, 5);
254             fail("expecting IllegalArgumentException");
255         } catch (IllegalArgumentException ex) {
256             // ignored
257         }
258 
259         try {
260             MathUtils.binomialCoefficientDouble(4, 5);
261             fail("expecting IllegalArgumentException");
262         } catch (IllegalArgumentException ex) {
263             // ignored
264         }
265 
266         try {
267             MathUtils.binomialCoefficientLog(4, 5);
268             fail("expecting IllegalArgumentException");
269         } catch (IllegalArgumentException ex) {
270             // ignored
271         }
272 
273         try {
274             MathUtils.binomialCoefficient(-1, -2);
275             fail("expecting IllegalArgumentException");
276         } catch (IllegalArgumentException ex) {
277             // ignored
278         }
279         try {
280             MathUtils.binomialCoefficientDouble(-1, -2);
281             fail("expecting IllegalArgumentException");
282         } catch (IllegalArgumentException ex) {
283             // ignored
284         }
285         try {
286             MathUtils.binomialCoefficientLog(-1, -2);
287             fail("expecting IllegalArgumentException");
288         } catch (IllegalArgumentException ex) {
289             // ignored
290         }
291 
292         try {
293             MathUtils.binomialCoefficient(67, 30);
294             fail("expecting ArithmeticException");
295         } catch (ArithmeticException ex) {
296             // ignored
297         }
298         try {
299             MathUtils.binomialCoefficient(67, 34);
300             fail("expecting ArithmeticException");
301         } catch (ArithmeticException ex) {
302             // ignored
303         }
304         double x = MathUtils.binomialCoefficientDouble(1030, 515);
305         assertTrue("expecting infinite binomial coefficient", Double
306             .isInfinite(x));
307     }
308 
309     public void testCompareTo() {
310       assertEquals(0, MathUtils.compareTo(152.33, 152.32, .011));
311       assertTrue(MathUtils.compareTo(152.308, 152.32, .011) < 0);
312       assertTrue(MathUtils.compareTo(152.33, 152.318, .011) > 0);
313     }
314     
315     public void testCosh() {
316         double x = 3.0;
317         double expected = 10.06766;
318         assertEquals(expected, MathUtils.cosh(x), 1.0e-5);
319     }
320 
321     public void testCoshNaN() {
322         assertTrue(Double.isNaN(MathUtils.cosh(Double.NaN)));
323     }
324 
325     public void testEquals() {
326         double[] testArray = {
327             Double.NaN,
328             Double.POSITIVE_INFINITY,
329             Double.NEGATIVE_INFINITY,
330             1d,
331             0d };
332         for (int i = 0; i < testArray.length; i++) {
333             for (int j = 0; j < testArray.length; j++) {
334                 if (i == j) {
335                     assertTrue(MathUtils.equals(testArray[i], testArray[j]));
336                     assertTrue(MathUtils.equals(testArray[j], testArray[i]));
337                 } else {
338                     assertTrue(!MathUtils.equals(testArray[i], testArray[j]));
339                     assertTrue(!MathUtils.equals(testArray[j], testArray[i]));
340                 }
341             }
342         }
343     }
344 
345     public void testEqualsWithAllowedDelta() {
346         assertTrue(MathUtils.equals(153.0000, 153.0000, .0625));
347         assertTrue(MathUtils.equals(153.0000, 153.0625, .0625));
348         assertTrue(MathUtils.equals(152.9375, 153.0000, .0625));
349         assertTrue(MathUtils.equals(Double.NaN, Double.NaN, 1.0));
350         assertTrue(MathUtils.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0));
351         assertTrue(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 1.0));
352         assertFalse(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0));
353         assertFalse(MathUtils.equals(153.0000, 153.0625, .0624));
354         assertFalse(MathUtils.equals(152.9374, 153.0000, .0625));
355     }
356 
357     public void testEqualsWithAllowedUlps() {
358         assertTrue(MathUtils.equals(153, 153, 1));
359 
360         assertTrue(MathUtils.equals(153, 153.00000000000003, 1));
361         assertFalse(MathUtils.equals(153, 153.00000000000006, 1));
362         assertTrue(MathUtils.equals(153, 152.99999999999997, 1));
363         assertFalse(MathUtils.equals(153, 152.99999999999994, 1));
364         
365         assertTrue(MathUtils.equals(-128, -127.99999999999999, 1));
366         assertFalse(MathUtils.equals(-128, -127.99999999999997, 1));
367         assertTrue(MathUtils.equals(-128, -128.00000000000003, 1));
368         assertFalse(MathUtils.equals(-128, -128.00000000000006, 1));
369 
370         assertTrue(MathUtils.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 1));
371         assertTrue(MathUtils.equals(Double.MAX_VALUE, Double.POSITIVE_INFINITY, 1));
372 
373         assertTrue(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 1));
374         assertTrue(MathUtils.equals(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY, 1));
375 
376 
377         assertTrue(MathUtils.equals(Double.NaN, Double.NaN, 1));
378 
379         assertFalse(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 100000));
380     }
381     
382     public void testArrayEquals() {
383         assertFalse(MathUtils.equals(new double[] { 1d }, null));
384         assertFalse(MathUtils.equals(null, new double[] { 1d }));
385         assertTrue(MathUtils.equals((double[]) null, (double[]) null));
386 
387         assertFalse(MathUtils.equals(new double[] { 1d }, new double[0]));
388         assertTrue(MathUtils.equals(new double[] { 1d }, new double[] { 1d }));
389         assertTrue(MathUtils.equals(new double[] {
390                                       Double.NaN, Double.POSITIVE_INFINITY,
391                                       Double.NEGATIVE_INFINITY, 1d, 0d
392                                     }, new double[] {
393                                       Double.NaN, Double.POSITIVE_INFINITY,
394                                       Double.NEGATIVE_INFINITY, 1d, 0d
395                                     }));
396         assertFalse(MathUtils.equals(new double[] { Double.POSITIVE_INFINITY },
397                                      new double[] { Double.NEGATIVE_INFINITY }));
398         assertFalse(MathUtils.equals(new double[] { 1d },
399                                      new double[] { MathUtils.nextAfter(1d, 2d) }));
400 
401     }
402 
403     public void testFactorial() {
404         for (int i = 1; i < 21; i++) {
405             assertEquals(i + "! ", factorial(i), MathUtils.factorial(i));
406             assertEquals(i + "! ", factorial(i), MathUtils.factorialDouble(i), Double.MIN_VALUE);
407             assertEquals(i + "! ", Math.log(factorial(i)), MathUtils.factorialLog(i), 10E-12);
408         }
409         
410         assertEquals("0", 1, MathUtils.factorial(0));
411         assertEquals("0", 1.0d, MathUtils.factorialDouble(0), 1E-14);
412         assertEquals("0", 0.0d, MathUtils.factorialLog(0), 1E-14);
413     }
414 
415     public void testFactorialFail() {
416         try {
417             MathUtils.factorial(-1);
418             fail("expecting IllegalArgumentException");
419         } catch (IllegalArgumentException ex) {
420             // ignored
421         }
422         try {
423             MathUtils.factorialDouble(-1);
424             fail("expecting IllegalArgumentException");
425         } catch (IllegalArgumentException ex) {
426             // ignored
427         }
428         try {
429             MathUtils.factorialLog(-1);
430             fail("expecting IllegalArgumentException");
431         } catch (IllegalArgumentException ex) {
432             // ignored
433         }
434         try {
435             MathUtils.factorial(21);
436             fail("expecting ArithmeticException");
437         } catch (ArithmeticException ex) {
438             // ignored
439         }
440         assertTrue("expecting infinite factorial value", Double.isInfinite(MathUtils.factorialDouble(171)));
441     }
442 
443     public void testGcd() {
444         int a = 30;
445         int b = 50;
446         int c = 77;
447 
448         assertEquals(0, MathUtils.gcd(0, 0));
449 
450         assertEquals(b, MathUtils.gcd(0, b));
451         assertEquals(a, MathUtils.gcd(a, 0));
452         assertEquals(b, MathUtils.gcd(0, -b));
453         assertEquals(a, MathUtils.gcd(-a, 0));
454 
455         assertEquals(10, MathUtils.gcd(a, b));
456         assertEquals(10, MathUtils.gcd(-a, b));
457         assertEquals(10, MathUtils.gcd(a, -b));
458         assertEquals(10, MathUtils.gcd(-a, -b));
459 
460         assertEquals(1, MathUtils.gcd(a, c));
461         assertEquals(1, MathUtils.gcd(-a, c));
462         assertEquals(1, MathUtils.gcd(a, -c));
463         assertEquals(1, MathUtils.gcd(-a, -c));
464 
465         assertEquals(3 * (1<<15), MathUtils.gcd(3 * (1<<20), 9 * (1<<15)));
466 
467         assertEquals(Integer.MAX_VALUE, MathUtils.gcd(Integer.MAX_VALUE, 0));
468         assertEquals(Integer.MAX_VALUE, MathUtils.gcd(-Integer.MAX_VALUE, 0));
469         assertEquals(1<<30, MathUtils.gcd(1<<30, -Integer.MIN_VALUE));
470         try {
471             // gcd(Integer.MIN_VALUE, 0) > Integer.MAX_VALUE
472             MathUtils.gcd(Integer.MIN_VALUE, 0);
473             fail("expecting ArithmeticException");
474         } catch (ArithmeticException expected) {
475             // expected
476         }
477         try {
478             // gcd(0, Integer.MIN_VALUE) > Integer.MAX_VALUE
479             MathUtils.gcd(0, Integer.MIN_VALUE);
480             fail("expecting ArithmeticException");
481         } catch (ArithmeticException expected) {
482             // expected
483         }
484         try {
485             // gcd(Integer.MIN_VALUE, Integer.MIN_VALUE) > Integer.MAX_VALUE
486             MathUtils.gcd(Integer.MIN_VALUE, Integer.MIN_VALUE);
487             fail("expecting ArithmeticException");
488         } catch (ArithmeticException expected) {
489             // expected
490         }
491     }
492 
493     public void testHash() {
494         double[] testArray = {
495             Double.NaN,
496             Double.POSITIVE_INFINITY,
497             Double.NEGATIVE_INFINITY,
498             1d,
499             0d,
500             1E-14,
501             (1 + 1E-14),
502             Double.MIN_VALUE,
503             Double.MAX_VALUE };
504         for (int i = 0; i < testArray.length; i++) {
505             for (int j = 0; j < testArray.length; j++) {
506                 if (i == j) {
507                     assertEquals(MathUtils.hash(testArray[i]), MathUtils.hash(testArray[j]));
508                     assertEquals(MathUtils.hash(testArray[j]), MathUtils.hash(testArray[i]));
509                 } else {
510                     assertTrue(MathUtils.hash(testArray[i]) != MathUtils.hash(testArray[j]));
511                     assertTrue(MathUtils.hash(testArray[j]) != MathUtils.hash(testArray[i]));
512                 }
513             }
514         }
515     }
516 
517     public void testArrayHash() {
518         assertEquals(0, MathUtils.hash((double[]) null));
519         assertEquals(MathUtils.hash(new double[] {
520                                       Double.NaN, Double.POSITIVE_INFINITY,
521                                       Double.NEGATIVE_INFINITY, 1d, 0d
522                                     }),
523                      MathUtils.hash(new double[] {
524                                       Double.NaN, Double.POSITIVE_INFINITY,
525                                       Double.NEGATIVE_INFINITY, 1d, 0d
526                                     }));
527         assertFalse(MathUtils.hash(new double[] { 1d }) ==
528                     MathUtils.hash(new double[] { MathUtils.nextAfter(1d, 2d) }));
529         assertFalse(MathUtils.hash(new double[] { 1d }) ==
530                     MathUtils.hash(new double[] { 1d, 1d }));
531     }
532     
533     /**
534      * Make sure that permuted arrays do not hash to the same value.
535      */
536     public void testPermutedArrayHash() {
537         double[] original = new double[10];
538         double[] permuted = new double[10];
539         RandomDataImpl random = new RandomDataImpl();
540         
541         // Generate 10 distinct random values
542         for (int i = 0; i < 10; i++) {
543             original[i] = random.nextUniform(i + 0.5, i + 0.75);
544         }
545         
546         // Generate a random permutation, making sure it is not the identity
547         boolean isIdentity = true;
548         do {
549             int[] permutation = random.nextPermutation(10, 10);
550             for (int i = 0; i < 10; i++) {
551                 if (i != permutation[i]) {
552                     isIdentity = false;
553                 }
554                 permuted[i] = original[permutation[i]];
555             }
556         } while (isIdentity);
557         
558         // Verify that permuted array has different hash
559         assertFalse(MathUtils.hash(original) == MathUtils.hash(permuted));
560     }
561 
562     public void testIndicatorByte() {
563         assertEquals((byte)1, MathUtils.indicator((byte)2));
564         assertEquals((byte)1, MathUtils.indicator((byte)0));
565         assertEquals((byte)(-1), MathUtils.indicator((byte)(-2)));
566     }
567 
568     public void testIndicatorDouble() {
569         double delta = 0.0;
570         assertEquals(1.0, MathUtils.indicator(2.0), delta);
571         assertEquals(1.0, MathUtils.indicator(0.0), delta);
572         assertEquals(-1.0, MathUtils.indicator(-2.0), delta);
573         assertEquals(Double.NaN, MathUtils.indicator(Double.NaN));
574     }
575 
576     public void testIndicatorFloat() {
577         float delta = 0.0F;
578         assertEquals(1.0F, MathUtils.indicator(2.0F), delta);
579         assertEquals(1.0F, MathUtils.indicator(0.0F), delta);
580         assertEquals(-1.0F, MathUtils.indicator(-2.0F), delta);
581     }
582 
583     public void testIndicatorInt() {
584         assertEquals(1, MathUtils.indicator((2)));
585         assertEquals(1, MathUtils.indicator((0)));
586         assertEquals((-1), MathUtils.indicator((-2)));
587     }
588 
589     public void testIndicatorLong() {
590         assertEquals(1L, MathUtils.indicator(2L));
591         assertEquals(1L, MathUtils.indicator(0L));
592         assertEquals(-1L, MathUtils.indicator(-2L));
593     }
594 
595     public void testIndicatorShort() {
596         assertEquals((short)1, MathUtils.indicator((short)2));
597         assertEquals((short)1, MathUtils.indicator((short)0));
598         assertEquals((short)(-1), MathUtils.indicator((short)(-2)));
599     }
600 
601     public void testLcm() {
602         int a = 30;
603         int b = 50;
604         int c = 77;
605 
606         assertEquals(0, MathUtils.lcm(0, b));
607         assertEquals(0, MathUtils.lcm(a, 0));
608         assertEquals(b, MathUtils.lcm(1, b));
609         assertEquals(a, MathUtils.lcm(a, 1));
610         assertEquals(150, MathUtils.lcm(a, b));
611         assertEquals(150, MathUtils.lcm(-a, b));
612         assertEquals(150, MathUtils.lcm(a, -b));
613         assertEquals(150, MathUtils.lcm(-a, -b));
614         assertEquals(2310, MathUtils.lcm(a, c));
615 
616         // Assert that no intermediate value overflows:
617         // The naive implementation of lcm(a,b) would be (a*b)/gcd(a,b)
618         assertEquals((1<<20)*15, MathUtils.lcm((1<<20)*3, (1<<20)*5));
619 
620         // Special case
621         assertEquals(0, MathUtils.lcm(0, 0));
622 
623         try {
624             // lcm == abs(MIN_VALUE) cannot be represented as a nonnegative int
625             MathUtils.lcm(Integer.MIN_VALUE, 1);
626             fail("Expecting ArithmeticException");
627         } catch (ArithmeticException ex) {
628             // expected
629         }
630         
631         try {
632             // lcm == abs(MIN_VALUE) cannot be represented as a nonnegative int
633             MathUtils.lcm(Integer.MIN_VALUE, 1<<20);
634             fail("Expecting ArithmeticException");
635         } catch (ArithmeticException ex) {
636             // expected
637         }
638 
639         try {
640             MathUtils.lcm(Integer.MAX_VALUE, Integer.MAX_VALUE - 1);
641             fail("Expecting ArithmeticException");
642         } catch (ArithmeticException ex) {
643             // expected
644         }
645     }
646 
647     public void testLog() {
648         assertEquals(2.0, MathUtils.log(2, 4), 0);
649         assertEquals(3.0, MathUtils.log(2, 8), 0);
650         assertTrue(Double.isNaN(MathUtils.log(-1, 1)));
651         assertTrue(Double.isNaN(MathUtils.log(1, -1)));
652         assertTrue(Double.isNaN(MathUtils.log(0, 0)));
653         assertEquals(0, MathUtils.log(0, 10), 0);
654         assertEquals(Double.NEGATIVE_INFINITY, MathUtils.log(10, 0), 0);
655     }
656 
657     public void testMulAndCheck() {
658         int big = Integer.MAX_VALUE;
659         int bigNeg = Integer.MIN_VALUE;
660         assertEquals(big, MathUtils.mulAndCheck(big, 1));
661         try {
662             MathUtils.mulAndCheck(big, 2);
663             fail("Expecting ArithmeticException");
664         } catch (ArithmeticException ex) {
665         }
666         try {
667             MathUtils.mulAndCheck(bigNeg, 2);
668             fail("Expecting ArithmeticException");
669         } catch (ArithmeticException ex) {
670         }
671     }
672 
673     public void testMulAndCheckLong() {
674         long max = Long.MAX_VALUE;
675         long min = Long.MIN_VALUE;
676         assertEquals(max, MathUtils.mulAndCheck(max, 1L));
677         assertEquals(min, MathUtils.mulAndCheck(min, 1L));
678         assertEquals(0L, MathUtils.mulAndCheck(max, 0L));
679         assertEquals(0L, MathUtils.mulAndCheck(min, 0L));
680         assertEquals(max, MathUtils.mulAndCheck(1L, max));
681         assertEquals(min, MathUtils.mulAndCheck(1L, min));
682         assertEquals(0L, MathUtils.mulAndCheck(0L, max));
683         assertEquals(0L, MathUtils.mulAndCheck(0L, min));
684         assertEquals(1L, MathUtils.mulAndCheck(-1L, -1L));
685         assertEquals(min, MathUtils.mulAndCheck(min / 2, 2));
686         testMulAndCheckLongFailure(max, 2L);
687         testMulAndCheckLongFailure(2L, max);
688         testMulAndCheckLongFailure(min, 2L);
689         testMulAndCheckLongFailure(2L, min);
690         testMulAndCheckLongFailure(min, -1L);
691         testMulAndCheckLongFailure(-1L, min);
692     }
693 
694     private void testMulAndCheckLongFailure(long a, long b) {
695         try {
696             MathUtils.mulAndCheck(a, b);
697             fail("Expecting ArithmeticException");
698         } catch (ArithmeticException ex) {
699             // success
700         }
701     }
702 
703     public void testNextAfter() {
704         // 0x402fffffffffffff 0x404123456789abcd -> 4030000000000000
705         assertEquals(16.0, MathUtils.nextAfter(15.999999999999998, 34.27555555555555), 0.0);
706 
707         // 0xc02fffffffffffff 0x404123456789abcd -> c02ffffffffffffe
708         assertEquals(-15.999999999999996, MathUtils.nextAfter(-15.999999999999998, 34.27555555555555), 0.0);
709 
710         // 0x402fffffffffffff 0x400123456789abcd -> 402ffffffffffffe
711         assertEquals(15.999999999999996, MathUtils.nextAfter(15.999999999999998, 2.142222222222222), 0.0);
712 
713         // 0xc02fffffffffffff 0x400123456789abcd -> c02ffffffffffffe
714         assertEquals(-15.999999999999996, MathUtils.nextAfter(-15.999999999999998, 2.142222222222222), 0.0);
715 
716         // 0x4020000000000000 0x404123456789abcd -> 4020000000000001
717         assertEquals(8.000000000000002, MathUtils.nextAfter(8.0, 34.27555555555555), 0.0);
718 
719         // 0xc020000000000000 0x404123456789abcd -> c01fffffffffffff
720         assertEquals(-7.999999999999999, MathUtils.nextAfter(-8.0, 34.27555555555555), 0.0);
721 
722         // 0x4020000000000000 0x400123456789abcd -> 401fffffffffffff
723         assertEquals(7.999999999999999, MathUtils.nextAfter(8.0, 2.142222222222222), 0.0);
724 
725         // 0xc020000000000000 0x400123456789abcd -> c01fffffffffffff
726         assertEquals(-7.999999999999999, MathUtils.nextAfter(-8.0, 2.142222222222222), 0.0);
727 
728         // 0x3f2e43753d36a223 0x3f2e43753d36a224 -> 3f2e43753d36a224
729         assertEquals(2.308922399667661E-4, MathUtils.nextAfter(2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
730 
731         // 0x3f2e43753d36a223 0x3f2e43753d36a223 -> 3f2e43753d36a224
732         assertEquals(2.308922399667661E-4, MathUtils.nextAfter(2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
733 
734         // 0x3f2e43753d36a223 0x3f2e43753d36a222 -> 3f2e43753d36a222
735         assertEquals(2.3089223996676603E-4, MathUtils.nextAfter(2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
736 
737         // 0x3f2e43753d36a223 0xbf2e43753d36a224 -> 3f2e43753d36a222
738         assertEquals(2.3089223996676603E-4, MathUtils.nextAfter(2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
739 
740         // 0x3f2e43753d36a223 0xbf2e43753d36a223 -> 3f2e43753d36a222
741         assertEquals(2.3089223996676603E-4, MathUtils.nextAfter(2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
742 
743         // 0x3f2e43753d36a223 0xbf2e43753d36a222 -> 3f2e43753d36a222
744         assertEquals(2.3089223996676603E-4, MathUtils.nextAfter(2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
745 
746         // 0xbf2e43753d36a223 0x3f2e43753d36a224 -> bf2e43753d36a222
747         assertEquals(-2.3089223996676603E-4, MathUtils.nextAfter(-2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
748 
749         // 0xbf2e43753d36a223 0x3f2e43753d36a223 -> bf2e43753d36a222
750         assertEquals(-2.3089223996676603E-4, MathUtils.nextAfter(-2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
751 
752         // 0xbf2e43753d36a223 0x3f2e43753d36a222 -> bf2e43753d36a222
753         assertEquals(-2.3089223996676603E-4, MathUtils.nextAfter(-2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
754 
755         // 0xbf2e43753d36a223 0xbf2e43753d36a224 -> bf2e43753d36a224
756         assertEquals(-2.308922399667661E-4, MathUtils.nextAfter(-2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
757 
758         // 0xbf2e43753d36a223 0xbf2e43753d36a223 -> bf2e43753d36a224
759         assertEquals(-2.308922399667661E-4, MathUtils.nextAfter(-2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
760 
761         // 0xbf2e43753d36a223 0xbf2e43753d36a222 -> bf2e43753d36a222
762         assertEquals(-2.3089223996676603E-4, MathUtils.nextAfter(-2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
763 
764     }
765 
766     public void testNextAfterSpecialCases() {
767         assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.NEGATIVE_INFINITY, 0)));
768         assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.POSITIVE_INFINITY, 0)));
769         assertTrue(Double.isNaN(MathUtils.nextAfter(Double.NaN, 0)));
770         assertTrue(Double.isInfinite(MathUtils.nextAfter(Double.MAX_VALUE, Double.POSITIVE_INFINITY)));
771         assertTrue(Double.isInfinite(MathUtils.nextAfter(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY)));
772         assertEquals(Double.MIN_VALUE, MathUtils.nextAfter(0, 1), 0);
773         assertEquals(-Double.MIN_VALUE, MathUtils.nextAfter(0, -1), 0);
774         assertEquals(0, MathUtils.nextAfter(Double.MIN_VALUE, -1), 0);
775         assertEquals(0, MathUtils.nextAfter(-Double.MIN_VALUE, 1), 0);
776     }
777 
778     public void testScalb() {
779         assertEquals( 0.0, MathUtils.scalb(0.0, 5), 1.0e-15);
780         assertEquals(32.0, MathUtils.scalb(1.0, 5), 1.0e-15);
781         assertEquals(1.0 / 32.0, MathUtils.scalb(1.0,  -5), 1.0e-15);
782         assertEquals(Math.PI, MathUtils.scalb(Math.PI, 0), 1.0e-15);
783         assertTrue(Double.isInfinite(MathUtils.scalb(Double.POSITIVE_INFINITY, 1)));
784         assertTrue(Double.isInfinite(MathUtils.scalb(Double.NEGATIVE_INFINITY, 1)));
785         assertTrue(Double.isNaN(MathUtils.scalb(Double.NaN, 1)));
786     }
787 
788     public void testNormalizeAngle() {
789         for (double a = -15.0; a <= 15.0; a += 0.1) {
790             for (double b = -15.0; b <= 15.0; b += 0.2) {
791                 double c = MathUtils.normalizeAngle(a, b);
792                 assertTrue((b - Math.PI) <= c);
793                 assertTrue(c <= (b + Math.PI));
794                 double twoK = Math.rint((a - c) / Math.PI);
795                 assertEquals(c, a - twoK * Math.PI, 1.0e-14);
796             }
797         }
798     }
799 
800     public void testRoundDouble() {
801         double x = 1.234567890;
802         assertEquals(1.23, MathUtils.round(x, 2), 0.0);
803         assertEquals(1.235, MathUtils.round(x, 3), 0.0);
804         assertEquals(1.2346, MathUtils.round(x, 4), 0.0);
805 
806         // JIRA MATH-151
807         assertEquals(39.25, MathUtils.round(39.245, 2), 0.0);
808         assertEquals(39.24, MathUtils.round(39.245, 2, BigDecimal.ROUND_DOWN), 0.0);
809         double xx = 39.0;
810         xx = xx + 245d / 1000d;
811         assertEquals(39.25, MathUtils.round(xx, 2), 0.0);
812 
813         // BZ 35904
814         assertEquals(30.1d, MathUtils.round(30.095d, 2), 0.0d);
815         assertEquals(30.1d, MathUtils.round(30.095d, 1), 0.0d);
816         assertEquals(33.1d, MathUtils.round(33.095d, 1), 0.0d);
817         assertEquals(33.1d, MathUtils.round(33.095d, 2), 0.0d);
818         assertEquals(50.09d, MathUtils.round(50.085d, 2), 0.0d);
819         assertEquals(50.19d, MathUtils.round(50.185d, 2), 0.0d);
820         assertEquals(50.01d, MathUtils.round(50.005d, 2), 0.0d);
821         assertEquals(30.01d, MathUtils.round(30.005d, 2), 0.0d);
822         assertEquals(30.65d, MathUtils.round(30.645d, 2), 0.0d);
823 
824         assertEquals(1.24, MathUtils.round(x, 2, BigDecimal.ROUND_CEILING), 0.0);
825         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_CEILING), 0.0);
826         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_CEILING), 0.0);
827         assertEquals(-1.23, MathUtils.round(-x, 2, BigDecimal.ROUND_CEILING), 0.0);
828         assertEquals(-1.234, MathUtils.round(-x, 3, BigDecimal.ROUND_CEILING), 0.0);
829         assertEquals(-1.2345, MathUtils.round(-x, 4, BigDecimal.ROUND_CEILING), 0.0);
830 
831         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_DOWN), 0.0);
832         assertEquals(1.234, MathUtils.round(x, 3, BigDecimal.ROUND_DOWN), 0.0);
833         assertEquals(1.2345, MathUtils.round(x, 4, BigDecimal.ROUND_DOWN), 0.0);
834         assertEquals(-1.23, MathUtils.round(-x, 2, BigDecimal.ROUND_DOWN), 0.0);
835         assertEquals(-1.234, MathUtils.round(-x, 3, BigDecimal.ROUND_DOWN), 0.0);
836         assertEquals(-1.2345, MathUtils.round(-x, 4, BigDecimal.ROUND_DOWN), 0.0);
837 
838         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_FLOOR), 0.0);
839         assertEquals(1.234, MathUtils.round(x, 3, BigDecimal.ROUND_FLOOR), 0.0);
840         assertEquals(1.2345, MathUtils.round(x, 4, BigDecimal.ROUND_FLOOR), 0.0);
841         assertEquals(-1.24, MathUtils.round(-x, 2, BigDecimal.ROUND_FLOOR), 0.0);
842         assertEquals(-1.235, MathUtils.round(-x, 3, BigDecimal.ROUND_FLOOR), 0.0);
843         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_FLOOR), 0.0);
844 
845         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
846         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
847         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
848         assertEquals(-1.23, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
849         assertEquals(-1.235, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
850         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
851         assertEquals(1.234, MathUtils.round(1.2345, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
852         assertEquals(-1.234, MathUtils.round(-1.2345, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
853 
854         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
855         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
856         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
857         assertEquals(-1.23, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
858         assertEquals(-1.235, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
859         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
860         assertEquals(1.234, MathUtils.round(1.2345, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
861         assertEquals(-1.234, MathUtils.round(-1.2345, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
862         assertEquals(1.236, MathUtils.round(1.2355, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
863         assertEquals(-1.236, MathUtils.round(-1.2355, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
864 
865         assertEquals(1.23, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
866         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
867         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
868         assertEquals(-1.23, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
869         assertEquals(-1.235, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
870         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
871         assertEquals(1.235, MathUtils.round(1.2345, 3, BigDecimal.ROUND_HALF_UP), 0.0);
872         assertEquals(-1.235, MathUtils.round(-1.2345, 3, BigDecimal.ROUND_HALF_UP), 0.0);
873 
874         assertEquals(-1.23, MathUtils.round(-1.23, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
875         assertEquals(1.23, MathUtils.round(1.23, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
876 
877         try {
878             MathUtils.round(1.234, 2, BigDecimal.ROUND_UNNECESSARY);
879             fail();
880         } catch (ArithmeticException ex) {
881             // success
882         }
883 
884         assertEquals(1.24, MathUtils.round(x, 2, BigDecimal.ROUND_UP), 0.0);
885         assertEquals(1.235, MathUtils.round(x, 3, BigDecimal.ROUND_UP), 0.0);
886         assertEquals(1.2346, MathUtils.round(x, 4, BigDecimal.ROUND_UP), 0.0);
887         assertEquals(-1.24, MathUtils.round(-x, 2, BigDecimal.ROUND_UP), 0.0);
888         assertEquals(-1.235, MathUtils.round(-x, 3, BigDecimal.ROUND_UP), 0.0);
889         assertEquals(-1.2346, MathUtils.round(-x, 4, BigDecimal.ROUND_UP), 0.0);
890 
891         try {
892             MathUtils.round(1.234, 2, 1923);
893             fail();
894         } catch (IllegalArgumentException ex) {
895             // success
896         }
897 
898         // MATH-151
899         assertEquals(39.25, MathUtils.round(39.245, 2, BigDecimal.ROUND_HALF_UP), 0.0);
900 
901         // special values
902         TestUtils.assertEquals(Double.NaN, MathUtils.round(Double.NaN, 2), 0.0);
903         assertEquals(0.0, MathUtils.round(0.0, 2), 0.0);
904         assertEquals(Double.POSITIVE_INFINITY, MathUtils.round(Double.POSITIVE_INFINITY, 2), 0.0);
905         assertEquals(Double.NEGATIVE_INFINITY, MathUtils.round(Double.NEGATIVE_INFINITY, 2), 0.0);
906     }
907 
908     public void testRoundFloat() {
909         float x = 1.234567890f;
910         assertEquals(1.23f, MathUtils.round(x, 2), 0.0);
911         assertEquals(1.235f, MathUtils.round(x, 3), 0.0);
912         assertEquals(1.2346f, MathUtils.round(x, 4), 0.0);
913 
914         // BZ 35904
915         assertEquals(30.1f, MathUtils.round(30.095f, 2), 0.0f);
916         assertEquals(30.1f, MathUtils.round(30.095f, 1), 0.0f);
917         assertEquals(50.09f, MathUtils.round(50.085f, 2), 0.0f);
918         assertEquals(50.19f, MathUtils.round(50.185f, 2), 0.0f);
919         assertEquals(50.01f, MathUtils.round(50.005f, 2), 0.0f);
920         assertEquals(30.01f, MathUtils.round(30.005f, 2), 0.0f);
921         assertEquals(30.65f, MathUtils.round(30.645f, 2), 0.0f);
922 
923         assertEquals(1.24f, MathUtils.round(x, 2, BigDecimal.ROUND_CEILING), 0.0);
924         assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_CEILING), 0.0);
925         assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_CEILING), 0.0);
926         assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_CEILING), 0.0);
927         assertEquals(-1.234f, MathUtils.round(-x, 3, BigDecimal.ROUND_CEILING), 0.0);
928         assertEquals(-1.2345f, MathUtils.round(-x, 4, BigDecimal.ROUND_CEILING), 0.0);
929 
930         assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_DOWN), 0.0);
931         assertEquals(1.234f, MathUtils.round(x, 3, BigDecimal.ROUND_DOWN), 0.0);
932         assertEquals(1.2345f, MathUtils.round(x, 4, BigDecimal.ROUND_DOWN), 0.0);
933         assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_DOWN), 0.0);
934         assertEquals(-1.234f, MathUtils.round(-x, 3, BigDecimal.ROUND_DOWN), 0.0);
935         assertEquals(-1.2345f, MathUtils.round(-x, 4, BigDecimal.ROUND_DOWN), 0.0);
936 
937         assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_FLOOR), 0.0);
938         assertEquals(1.234f, MathUtils.round(x, 3, BigDecimal.ROUND_FLOOR), 0.0);
939         assertEquals(1.2345f, MathUtils.round(x, 4, BigDecimal.ROUND_FLOOR), 0.0);
940         assertEquals(-1.24f, MathUtils.round(-x, 2, BigDecimal.ROUND_FLOOR), 0.0);
941         assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_FLOOR), 0.0);
942         assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_FLOOR), 0.0);
943 
944         assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
945         assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
946         assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
947         assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_DOWN), 0.0);
948         assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
949         assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_DOWN), 0.0);
950         assertEquals(1.234f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
951         assertEquals(-1.234f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_DOWN), 0.0);
952 
953         assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
954         assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
955         assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
956         assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_EVEN), 0.0);
957         assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
958         assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_EVEN), 0.0);
959         assertEquals(1.234f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
960         assertEquals(-1.234f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
961         assertEquals(1.236f, MathUtils.round(1.2355f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
962         assertEquals(-1.236f, MathUtils.round(-1.2355f, 3, BigDecimal.ROUND_HALF_EVEN), 0.0);
963 
964         assertEquals(1.23f, MathUtils.round(x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
965         assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
966         assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
967         assertEquals(-1.23f, MathUtils.round(-x, 2, BigDecimal.ROUND_HALF_UP), 0.0);
968         assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_HALF_UP), 0.0);
969         assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_HALF_UP), 0.0);
970         assertEquals(1.235f, MathUtils.round(1.2345f, 3, BigDecimal.ROUND_HALF_UP), 0.0);
971         assertEquals(-1.235f, MathUtils.round(-1.2345f, 3, BigDecimal.ROUND_HALF_UP), 0.0);
972 
973         assertEquals(-1.23f, MathUtils.round(-1.23f, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
974         assertEquals(1.23f, MathUtils.round(1.23f, 2, BigDecimal.ROUND_UNNECESSARY), 0.0);
975 
976         try {
977             MathUtils.round(1.234f, 2, BigDecimal.ROUND_UNNECESSARY);
978             fail();
979         } catch (ArithmeticException ex) {
980             // success
981         }
982 
983         assertEquals(1.24f, MathUtils.round(x, 2, BigDecimal.ROUND_UP), 0.0);
984         assertEquals(1.235f, MathUtils.round(x, 3, BigDecimal.ROUND_UP), 0.0);
985         assertEquals(1.2346f, MathUtils.round(x, 4, BigDecimal.ROUND_UP), 0.0);
986         assertEquals(-1.24f, MathUtils.round(-x, 2, BigDecimal.ROUND_UP), 0.0);
987         assertEquals(-1.235f, MathUtils.round(-x, 3, BigDecimal.ROUND_UP), 0.0);
988         assertEquals(-1.2346f, MathUtils.round(-x, 4, BigDecimal.ROUND_UP), 0.0);
989 
990         try {
991             MathUtils.round(1.234f, 2, 1923);
992             fail();
993         } catch (IllegalArgumentException ex) {
994             // success
995         }
996 
997         // special values
998         TestUtils.assertEquals(Float.NaN, MathUtils.round(Float.NaN, 2), 0.0f);
999         assertEquals(0.0f, MathUtils.round(0.0f, 2), 0.0f);
1000         assertEquals(Float.POSITIVE_INFINITY, MathUtils.round(Float.POSITIVE_INFINITY, 2), 0.0f);
1001         assertEquals(Float.NEGATIVE_INFINITY, MathUtils.round(Float.NEGATIVE_INFINITY, 2), 0.0f);
1002     }
1003 
1004     public void testSignByte() {
1005         assertEquals((byte) 1, MathUtils.sign((byte) 2));
1006         assertEquals((byte) 0, MathUtils.sign((byte) 0));
1007         assertEquals((byte) (-1), MathUtils.sign((byte) (-2)));
1008     }
1009 
1010     public void testSignDouble() {
1011         double delta = 0.0;
1012         assertEquals(1.0, MathUtils.sign(2.0), delta);
1013         assertEquals(0.0, MathUtils.sign(0.0), delta);
1014         assertEquals(-1.0, MathUtils.sign(-2.0), delta);
1015         TestUtils.assertSame(-0. / 0., MathUtils.sign(Double.NaN));
1016     }
1017 
1018     public void testSignFloat() {
1019         float delta = 0.0F;
1020         assertEquals(1.0F, MathUtils.sign(2.0F), delta);
1021         assertEquals(0.0F, MathUtils.sign(0.0F), delta);
1022         assertEquals(-1.0F, MathUtils.sign(-2.0F), delta);
1023         TestUtils.assertSame(Float.NaN, MathUtils.sign(Float.NaN));
1024     }
1025 
1026     public void testSignInt() {
1027         assertEquals(1, MathUtils.sign(2));
1028         assertEquals(0, MathUtils.sign(0));
1029         assertEquals((-1), MathUtils.sign((-2)));
1030     }
1031 
1032     public void testSignLong() {
1033         assertEquals(1L, MathUtils.sign(2L));
1034         assertEquals(0L, MathUtils.sign(0L));
1035         assertEquals(-1L, MathUtils.sign(-2L));
1036     }
1037 
1038     public void testSignShort() {
1039         assertEquals((short) 1, MathUtils.sign((short) 2));
1040         assertEquals((short) 0, MathUtils.sign((short) 0));
1041         assertEquals((short) (-1), MathUtils.sign((short) (-2)));
1042     }
1043 
1044     public void testSinh() {
1045         double x = 3.0;
1046         double expected = 10.01787;
1047         assertEquals(expected, MathUtils.sinh(x), 1.0e-5);
1048     }
1049 
1050     public void testSinhNaN() {
1051         assertTrue(Double.isNaN(MathUtils.sinh(Double.NaN)));
1052     }
1053 
1054     public void testSubAndCheck() {
1055         int big = Integer.MAX_VALUE;
1056         int bigNeg = Integer.MIN_VALUE;
1057         assertEquals(big, MathUtils.subAndCheck(big, 0));
1058         assertEquals(bigNeg + 1, MathUtils.subAndCheck(bigNeg, -1));
1059         assertEquals(-1, MathUtils.subAndCheck(bigNeg, -big));
1060         try {
1061             MathUtils.subAndCheck(big, -1);
1062             fail("Expecting ArithmeticException");
1063         } catch (ArithmeticException ex) {
1064         }
1065         try {
1066             MathUtils.subAndCheck(bigNeg, 1);
1067             fail("Expecting ArithmeticException");
1068         } catch (ArithmeticException ex) {
1069         }
1070     }
1071 
1072     public void testSubAndCheckErrorMessage() {
1073         int big = Integer.MAX_VALUE;
1074         try {
1075             MathUtils.subAndCheck(big, -1);
1076             fail("Expecting ArithmeticException");
1077         } catch (ArithmeticException ex) {
1078             assertEquals("overflow: subtract", ex.getMessage());
1079         }
1080     }
1081 
1082     public void testSubAndCheckLong() {
1083         long max = Long.MAX_VALUE;
1084         long min = Long.MIN_VALUE;
1085         assertEquals(max, MathUtils.subAndCheck(max, 0));
1086         assertEquals(min, MathUtils.subAndCheck(min, 0));
1087         assertEquals(-max, MathUtils.subAndCheck(0, max));
1088         assertEquals(min + 1, MathUtils.subAndCheck(min, -1));
1089         // min == -1-max
1090         assertEquals(-1, MathUtils.subAndCheck(-max - 1, -max));
1091         assertEquals(max, MathUtils.subAndCheck(-1, -1 - max));
1092         testSubAndCheckLongFailure(0L, min);
1093         testSubAndCheckLongFailure(max, -1L);
1094         testSubAndCheckLongFailure(min, 1L);
1095     }
1096 
1097     private void testSubAndCheckLongFailure(long a, long b) {
1098         try {
1099             MathUtils.subAndCheck(a, b);
1100             fail("Expecting ArithmeticException");
1101         } catch (ArithmeticException ex) {
1102             // success
1103         }
1104 
1105     }
1106 
1107     public void testPow() {
1108 
1109         assertEquals(1801088541, MathUtils.pow(21, 7));
1110         assertEquals(1, MathUtils.pow(21, 0));
1111         try {
1112             MathUtils.pow(21, -7);
1113             fail("Expecting IllegalArgumentException");
1114         } catch (IllegalArgumentException e) {
1115             // expected behavior
1116         }
1117 
1118         assertEquals(1801088541, MathUtils.pow(21, 7l));
1119         assertEquals(1, MathUtils.pow(21, 0l));
1120         try {
1121             MathUtils.pow(21, -7l);
1122             fail("Expecting IllegalArgumentException");
1123         } catch (IllegalArgumentException e) {
1124             // expected behavior
1125         }
1126 
1127         assertEquals(1801088541l, MathUtils.pow(21l, 7));
1128         assertEquals(1l, MathUtils.pow(21l, 0));
1129         try {
1130             MathUtils.pow(21l, -7);
1131             fail("Expecting IllegalArgumentException");
1132         } catch (IllegalArgumentException e) {
1133             // expected behavior
1134         }
1135 
1136         assertEquals(1801088541l, MathUtils.pow(21l, 7l));
1137         assertEquals(1l, MathUtils.pow(21l, 0l));
1138         try {
1139             MathUtils.pow(21l, -7l);
1140             fail("Expecting IllegalArgumentException");
1141         } catch (IllegalArgumentException e) {
1142             // expected behavior
1143         }
1144 
1145         BigInteger twentyOne = BigInteger.valueOf(21l);
1146         assertEquals(BigInteger.valueOf(1801088541l), MathUtils.pow(twentyOne, 7));
1147         assertEquals(BigInteger.ONE, MathUtils.pow(twentyOne, 0));
1148         try {
1149             MathUtils.pow(twentyOne, -7);
1150             fail("Expecting IllegalArgumentException");
1151         } catch (IllegalArgumentException e) {
1152             // expected behavior
1153         }
1154 
1155         assertEquals(BigInteger.valueOf(1801088541l), MathUtils.pow(twentyOne, 7l));
1156         assertEquals(BigInteger.ONE, MathUtils.pow(twentyOne, 0l));
1157         try {
1158             MathUtils.pow(twentyOne, -7l);
1159             fail("Expecting IllegalArgumentException");
1160         } catch (IllegalArgumentException e) {
1161             // expected behavior
1162         }
1163 
1164         assertEquals(BigInteger.valueOf(1801088541l), MathUtils.pow(twentyOne, BigInteger.valueOf(7l)));
1165         assertEquals(BigInteger.ONE, MathUtils.pow(twentyOne, BigInteger.ZERO));
1166         try {
1167             MathUtils.pow(twentyOne, BigInteger.valueOf(-7l));
1168             fail("Expecting IllegalArgumentException");
1169         } catch (IllegalArgumentException e) {
1170             // expected behavior
1171         }
1172 
1173         BigInteger bigOne =
1174             new BigInteger("1543786922199448028351389769265814882661837148" +
1175                            "4763915343722775611762713982220306372888519211" +
1176                            "560905579993523402015636025177602059044911261");
1177         assertEquals(bigOne, MathUtils.pow(twentyOne, 103));
1178         assertEquals(bigOne, MathUtils.pow(twentyOne, 103l));
1179         assertEquals(bigOne, MathUtils.pow(twentyOne, BigInteger.valueOf(103l)));
1180         
1181     }
1182 
1183     public void testL1DistanceDouble() {
1184         double[] p1 = { 2.5,  0.0 };
1185         double[] p2 = { -0.5, 4.0 };
1186         assertEquals(7.0, MathUtils.distance1(p1, p2));
1187     }
1188 
1189     public void testL1DistanceInt() {
1190         int[] p1 = { 3, 0 };
1191         int[] p2 = { 0, 4 };
1192         assertEquals(7, MathUtils.distance1(p1, p2));
1193     }
1194 
1195     public void testL2DistanceDouble() {
1196         double[] p1 = { 2.5,  0.0 };
1197         double[] p2 = { -0.5, 4.0 };
1198         assertEquals(5.0, MathUtils.distance(p1, p2));
1199     }
1200 
1201     public void testL2DistanceInt() {
1202         int[] p1 = { 3, 0 };
1203         int[] p2 = { 0, 4 };
1204         assertEquals(5.0, MathUtils.distance(p1, p2));
1205     }
1206 
1207     public void testLInfDistanceDouble() {
1208         double[] p1 = { 2.5,  0.0 };
1209         double[] p2 = { -0.5, 4.0 };
1210         assertEquals(4.0, MathUtils.distanceInf(p1, p2));
1211     }
1212 
1213     public void testLInfDistanceInt() {
1214         int[] p1 = { 3, 0 };
1215         int[] p2 = { 0, 4 };
1216         assertEquals(4, MathUtils.distanceInf(p1, p2));
1217     }
1218 
1219 }