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 }