View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.sampling.distribution;
18  
19  import org.apache.commons.math3.special.Gamma;
20  import org.apache.commons.rng.sampling.distribution.InternalUtils.FactorialLog;
21  import org.junit.Assert;
22  import org.junit.Test;
23  
24  /**
25   * Test for the {@link InternalUtils}.
26   */
27  public class InternalUtilsTest {
28      /** The maximum value for n! that is representable as a long. */
29      private static final int MAX_REPRESENTABLE = 20;
30  
31      @Test
32      public void testFactorial() {
33          Assert.assertEquals(1L, InternalUtils.factorial(0));
34          long result = 1;
35          for (int n = 1; n <= MAX_REPRESENTABLE; n++) {
36              result *= n;
37              Assert.assertEquals(result, InternalUtils.factorial(n));
38          }
39      }
40  
41      @Test(expected = IndexOutOfBoundsException.class)
42      public void testFactorialThrowsWhenNegative() {
43          InternalUtils.factorial(-1);
44      }
45  
46      @Test(expected = IndexOutOfBoundsException.class)
47      public void testFactorialThrowsWhenNotRepresentableAsLong() {
48          InternalUtils.factorial(MAX_REPRESENTABLE + 1);
49      }
50  
51      @Test
52      public void testFactorialLog() {
53          // Cache size allows some of the factorials to be cached and some
54          // to be under the precomputed factorials.
55          FactorialLog factorialLog = FactorialLog.create().withCache(MAX_REPRESENTABLE / 2);
56          Assert.assertEquals(0, factorialLog.value(0), 1e-10);
57          for (int n = 1; n <= MAX_REPRESENTABLE + 5; n++) {
58              // Use Commons math to compute logGamma(1 + n);
59              double expected = Gamma.logGamma(1 + n);
60              Assert.assertEquals(expected, factorialLog.value(n), 1e-10);
61          }
62      }
63  
64      @Test
65      public void testFactorialLogCacheSizeAboveRepresentableFactorials() {
66          final int limit = MAX_REPRESENTABLE + 5;
67          FactorialLog factorialLog = FactorialLog.create().withCache(limit);
68          for (int n = MAX_REPRESENTABLE; n <= limit; n++) {
69              // Use Commons math to compute logGamma(1 + n);
70              double expected = Gamma.logGamma(1 + n);
71              Assert.assertEquals(expected, factorialLog.value(n), 1e-10);
72          }
73      }
74  
75      @Test
76      public void testFactorialLogCacheExpansion() {
77          // There is no way to determine if the cache values were reused but this test
78          // exercises the method to ensure it does not error.
79          final FactorialLog factorialLog = FactorialLog.create()
80                                                        // Edge case where cache should not be copied (<2)
81                                                        .withCache(1)
82                                                        // Expand
83                                                        .withCache(5)
84                                                        // Expand more
85                                                        .withCache(10)
86                                                        // Contract
87                                                        .withCache(5);
88          for (int n = 1; n <= 5; n++) {
89              // Use Commons math to compute logGamma(1 + n);
90              double expected = Gamma.logGamma(1 + n);
91              Assert.assertEquals(expected, factorialLog.value(n), 1e-10);
92          }
93      }
94  
95      @Test(expected = IndexOutOfBoundsException.class)
96      public void testLogFactorialThrowsWhenNegative() {
97          FactorialLog.create().value(-1);
98      }
99  
100     @Test(expected = NegativeArraySizeException.class)
101     public void testLogFactorialWithCacheThrowsWhenNegative() {
102         FactorialLog.create().withCache(-1);
103     }
104 }