    1   /*
    2    * Copyright 2003-2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.math.util;
    17
    18  import junit.framework.Test;
    19  import junit.framework.TestCase;
    20  import junit.framework.TestSuite;
    21
    22  /***
    23   * Test cases for the MathUtils class.
    24   *
    25   * @version $Revision: 1.15 $ $Date: 2004/10/14 04:01:04 $
    26   */
    27
    28  public final class MathUtilsTest extends TestCase {
    29
    30      public MathUtilsTest(String name) {
    31          super(name);
    32      }
    33
    34      public void setUp() {
    35      }
    36
    37      public static Test suite() {
    38          TestSuite suite = new TestSuite(MathUtilsTest.class);
    39          suite.setName("MathUtils Tests");
    40          return suite;
    41      }
    42
    43      public void testBinomialCoefficient() {
    44          long[] bcoef5 = {1,5,10,10,5,1};
    45          long[] bcoef6 = {1,6,15,20,15,6,1};
    46          for (int i = 0; i < 6; i++) {
    47              assertEquals("5 choose " + i, bcoef5[i],
    48                  MathUtils.binomialCoefficient(5,i));
    49          }
    50          for (int i = 0; i < 7; i++) {
    51              assertEquals("6 choose " + i, bcoef6[i],
    52                  MathUtils.binomialCoefficient(6,i));
    53          }
    54
    55          for (int n = 1; n < 10; n++) {
    56              for (int k = 0; k <= n; k++) {
    57                  assertEquals(n + " choose " + k, binomialCoefficient(n, k),
    58                      MathUtils.binomialCoefficient(n, k));
    59                  assertEquals(n + " choose " + k,(double) binomialCoefficient(n, k),
    60                      MathUtils.binomialCoefficientDouble(n, k),Double.MIN_VALUE);
    61                  assertEquals(n + " choose " + k,
    62                      Math.log((double) binomialCoefficient(n, k)),
    63                      MathUtils.binomialCoefficientLog(n, k),10E-12);
    64              }
    65          }
    66
    67        /*
    68         * Takes a long time for recursion to unwind, but succeeds
    69         * and yields exact value = 2,333,606,220
    70
    71          assertEquals(MathUtils.binomialCoefficient(34,17),
    72              binomialCoefficient(34,17));
    73         */
    74      }
    75
    76      /*** Verify that b(0,0) = 1 */
    77      public void test0Choose0() {
    78          assertEquals(MathUtils.binomialCoefficientDouble(0, 0), 1d, 0);
    79          assertEquals(MathUtils.binomialCoefficientLog(0, 0), 0d, 0);
    80          assertEquals(MathUtils.binomialCoefficient(0, 0), 1);
    81      }
    82
    83      public void testBinomialCoefficientFail() {
    84          try {
    85              long x = MathUtils.binomialCoefficient(4,5);
    86              fail ("expecting IllegalArgumentException");
    87          } catch (IllegalArgumentException ex) {
    88              ;
    89          }
    90
    91          try {
    92              double x = MathUtils.binomialCoefficientDouble(4,5);
    93              fail ("expecting IllegalArgumentException");
    94          } catch (IllegalArgumentException ex) {
    95              ;
    96          }
    97
    98          try {
    99              double x = MathUtils.binomialCoefficientLog(4,5);
    100             fail ("expecting IllegalArgumentException");
    101         } catch (IllegalArgumentException ex) {
    102             ;
    103         }
    104         try {
    105             long x = MathUtils.binomialCoefficient(67,34);
    106             fail ("expecting ArithmeticException");
    107         } catch (ArithmeticException ex) {
    108             ;
    109         }
    110         double x = MathUtils.binomialCoefficientDouble(1030,515);
    111         assertTrue("expecting infinite binomial coefficient",
    112             Double.isInfinite(x));
    113     }
    114
    115     public void testFactorial() {
    116         for (int i = 1; i < 10; i++) {
    117             assertEquals(i + "! ",factorial(i),MathUtils.factorial(i));
    118             assertEquals(i + "! ",(double)factorial(i),
    119                 MathUtils.factorialDouble(i),Double.MIN_VALUE);
    120             assertEquals(i + "! ",Math.log((double)factorial(i)),
    121                 MathUtils.factorialLog(i),10E-12);
    122         }
    123         assertEquals("0", 1, MathUtils.factorial(0));
    124         assertEquals("0", 1.0d, MathUtils.factorialDouble(0), 1E-14);
    125         assertEquals("0", 0.0d, MathUtils.factorialLog(0), 1E-14);
    126     }
    127
    128     public void testFactorialFail() {
    129         try {
    130             long x = MathUtils.factorial(-1);
    131             fail ("expecting IllegalArgumentException");
    132         } catch (IllegalArgumentException ex) {
    133             ;
    134         }
    135         try {
    136             double x = MathUtils.factorialDouble(-1);
    137             fail ("expecting IllegalArgumentException");
    138         } catch (IllegalArgumentException ex) {
    139             ;
    140         }
    141         try {
    142             double x = MathUtils.factorialLog(-1);
    143             fail ("expecting IllegalArgumentException");
    144         } catch (IllegalArgumentException ex) {
    145             ;
    146         }
    147         try {
    148             double x = MathUtils.factorial(21);
    149             fail ("expecting ArithmeticException");
    150         } catch (ArithmeticException ex) {
    151             ;
    152         }
    153         assertTrue("expecting infinite factorial value",
    154             Double.isInfinite(MathUtils.factorialDouble(171)));
    155     }
    156
    157
    158     /***
    159      * Exact recursive implementation to test against
    160      */
    161     private long binomialCoefficient(int n, int k) {
    162         if ((n == k) || (k == 0)) {
    163             return 1;
    164         }
    165         if ((k == 1) || (k == n - 1)) {
    166             return n;
    167         }
    168         return binomialCoefficient(n - 1, k - 1) +
    169             binomialCoefficient(n - 1, k);
    170     }
    171
    172     /***
    173      * Finds the largest values of n for which binomialCoefficient and
    174      * binomialCoefficientDouble will return values that fit in a long, double,
    175      * resp.  Remove comments around test below to get this in test-report
    176      *
    177         public void testLimits() {
    178             findBinomialLimits();
    179         }
    180      */
    181
    182     private void findBinomialLimits() {
    183         /***
    184          * will kick out 66 as the limit for long
    185          */
    186         boolean foundLimit = false;
    187         int test = 10;
    188         while (!foundLimit) {
    189             try {
    190                 double x = MathUtils.binomialCoefficient(test, test / 2);
    191             } catch (ArithmeticException ex) {
    192                 foundLimit = true;
    193                 System.out.println
    194                     ("largest n for binomialCoefficient = " + (test - 1) );
    195             }
    196             test++;
    197         }
    198
    199        /***
    200         * will kick out 1029 as the limit for double
    201         */
    202         foundLimit = false;
    203         test = 10;
    204         while (!foundLimit) {
    205             double x = MathUtils.binomialCoefficientDouble(test, test / 2);
    206             if (Double.isInfinite(x)) {
    207                 foundLimit = true;
    208                 System.out.println
    209                     ("largest n for binomialCoefficientD = " + (test - 1) );
    210             }
    211             test++;
    212         }
    213     }
    214
    215     /***
    216      * Finds the largest values of n for which factiorial and
    217      * factorialDouble will return values that fit in a long, double,
    218      * resp.  Remove comments around test below to get this in test-report
    219
    220         public void testFactiorialLimits() {
    221             findFactorialLimits();
    222         }
    223      */
    224
    225     private void findFactorialLimits() {
    226         /***
    227          * will kick out 20 as the limit for long
    228          */
    229         boolean foundLimit = false;
    230         int test = 10;
    231         while (!foundLimit) {
    232             try {
    233                 double x = MathUtils.factorial(test);
    234             } catch (ArithmeticException ex) {
    235                 foundLimit = true;
    236                 System.out.println
    237                     ("largest n for factorial = " + (test - 1) );
    238             }
    239             test++;
    240         }
    241
    242        /***
    243         * will kick out 170 as the limit for double
    244         */
    245         foundLimit = false;
    246         test = 10;
    247         while (!foundLimit) {
    248             double x = MathUtils.factorialDouble(test);
    249             if (Double.isInfinite(x)) {
    250                 foundLimit = true;
    251                 System.out.println
    252                     ("largest n for factorialDouble = " + (test - 1) );
    253             }
    254             test++;
    255         }
    256     }
    257
    258
    259     /***
    260      * Exact direct multiplication implementation to test against
    261      */
    262     private long factorial(int n) {
    263         long result = 1;
    264         for (int i = 2; i <= n; i++) {
    265             result *= i;
    266         }
    267         return result;
    268     }
    269
    270     public void testSignDouble() {
    271         double delta = 0.0 ;
    272         assertEquals( 1.0, MathUtils.indicator( 2.0 ), delta ) ;
    273         assertEquals( -1.0, MathUtils.indicator( -2.0 ), delta ) ;
    274     }
    275
    276     public void testSignFloat() {
    277         float delta = 0.0F ;
    278         assertEquals( 1.0F, MathUtils.indicator( 2.0F ), delta ) ;
    279         assertEquals( -1.0F, MathUtils.indicator( -2.0F ), delta ) ;
    280     }
    281
    282     public void testSignByte() {
    283         assertEquals( (byte)1, MathUtils.indicator( (byte)2 ) ) ;
    284         assertEquals( (byte)(-1), MathUtils.indicator( (byte)(-2) ) ) ;
    285     }
    286
    287     public void testSignShort() {
    288         assertEquals( (short)1, MathUtils.indicator( (short)2 ) ) ;
    289         assertEquals( (short)(-1), MathUtils.indicator( (short)(-2) ) ) ;
    290     }
    291
    292     public void testSignInt() {
    293         assertEquals( (int)1, MathUtils.indicator( (int)(2) ) ) ;
    294         assertEquals( (int)(-1), MathUtils.indicator( (int)(-2) ) ) ;
    295     }
    296
    297     public void testSignLong() {
    298         assertEquals( 1L, MathUtils.indicator( 2L ) ) ;
    299         assertEquals( -1L, MathUtils.indicator( -2L ) ) ;
    300     }
    301
    302     public void testIndicatorDouble() {
    303         double delta = 0.0 ;
    304         assertEquals( 1.0, MathUtils.indicator( 2.0 ), delta ) ;
    305         assertEquals( 1.0, MathUtils.indicator( 0.0 ), delta ) ;
    306         assertEquals( -1.0, MathUtils.indicator( -2.0 ), delta ) ;
    307     }
    308
    309     public void testIndicatorFloat() {
    310         float delta = 0.0F ;
    311         assertEquals( 1.0F, MathUtils.indicator( 2.0F ), delta ) ;
    312         assertEquals( 1.0F, MathUtils.indicator( 0.0F ), delta ) ;
    313         assertEquals( -1.0F, MathUtils.indicator( -2.0F ), delta ) ;
    314     }
    315
    316     public void testIndicatorByte() {
    317         assertEquals( (byte)1, MathUtils.indicator( (byte)2 ) ) ;
    318         assertEquals( (byte)1, MathUtils.indicator( (byte)0 ) ) ;
    319         assertEquals( (byte)(-1), MathUtils.indicator( (byte)(-2) ) ) ;
    320     }
    321
    322     public void testIndicatorShort() {
    323         assertEquals( (short)1, MathUtils.indicator( (short)2 ) ) ;
    324         assertEquals( (short)1, MathUtils.indicator( (short)0 ) ) ;
    325         assertEquals( (short)(-1), MathUtils.indicator( (short)(-2) ) ) ;
    326     }
    327
    328     public void testIndicatorInt() {
    329         assertEquals( (int)1, MathUtils.indicator( (int)(2) ) ) ;
    330         assertEquals( (int)1, MathUtils.indicator( (int)(0) ) ) ;
    331         assertEquals( (int)(-1), MathUtils.indicator( (int)(-2) ) ) ;
    332     }
    333
    334     public void testIndicatorLong() {
    335         assertEquals( 1L, MathUtils.indicator( 2L ) ) ;
    336         assertEquals( 1L, MathUtils.indicator( 0L ) ) ;
    337         assertEquals( -1L, MathUtils.indicator( -2L ) ) ;
    338     }
    339
    340     public void testCosh() {
    341         double x = 3.0;
    342         double expected = 10.06766;
    343         assertEquals(expected, MathUtils.cosh(x), 1.0e-5);
    344     }
    345
    346     public void testSinh() {
    347         double x = 3.0;
    348         double expected = 10.01787;
    349         assertEquals(expected, MathUtils.sinh(x), 1.0e-5);
    350     }
    351
    352     public void testCoshNaN() {
    353         assertTrue(Double.isNaN(MathUtils.cosh(Double.NaN)));
    354     }
    355
    356     public void testSinhNaN() {
    357         assertTrue(Double.isNaN(MathUtils.sinh(Double.NaN)));
    358     }
    359
    360     public void testEquals() {
    361         double[] testArray = {Double.NaN, Double.POSITIVE_INFINITY,
    362                 Double.NEGATIVE_INFINITY, 1d, 0d};
    363         for (int i = 0; i < testArray.length; i++) {
    364             for (int j = 0; j < testArray.length; j ++) {
    365                 if (i == j) {
    366                     assertTrue(MathUtils.equals(testArray[i], testArray[j]));
    367                     assertTrue(MathUtils.equals(testArray[j], testArray[i]));
    368                 } else {
    369                     assertTrue(!MathUtils.equals(testArray[i], testArray[j]));
    370                     assertTrue(!MathUtils.equals(testArray[j], testArray[i]));
    371                 }
    372             }
    373         }
    374     }
    375
    376     public void testHash() {
    377         double[] testArray = {Double.NaN, Double.POSITIVE_INFINITY,
    378                 Double.NEGATIVE_INFINITY, 1d, 0d, 1E-14, (1 + 1E-14),
    379                 Double.MIN_VALUE, Double.MAX_VALUE};
    380         for (int i = 0; i < testArray.length; i++) {
    381             for (int j = 0; j < testArray.length; j ++) {
    382                 if (i == j) {
    383                     assertEquals(MathUtils.hash(testArray[i]), MathUtils.hash(testArray[j]));
    384                     assertEquals(MathUtils.hash(testArray[j]), MathUtils.hash(testArray[i]));
    385                 } else {
    386                     assertTrue(MathUtils.hash(testArray[i]) != MathUtils.hash(testArray[j]));
    387                     assertTrue(MathUtils.hash(testArray[j]) != MathUtils.hash(testArray[i]));
    388                 }
    389             }
    390         }
    391     }
    392 }