View Javadoc
1   /*
2    * Copyright (C) 2023 Alberto Irurueta Carro (alberto@irurueta.com)
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 com.irurueta.numerical;
17  
18  /**
19   * Estimates factorial values as long integer values.
20   */
21  public class LongFactorialEstimator {
22  
23      /**
24       * Cache size for factorial values that can be represented without overflowing with long
25       * precision.
26       * Values up to 20! are representable, 21! overflows.
27       */
28      public static final int CACHE_SIZE = 21;
29  
30      /**
31       * Cache of values.
32       */
33      private final long[] cache;
34  
35      /**
36       * Constructor with default cache size.
37       */
38      public LongFactorialEstimator() {
39          this(CACHE_SIZE);
40      }
41  
42      /**
43       * Constructor.
44       *
45       * @param cacheSize size of cache.
46       * @throws IllegalArgumentException if provided value is less than 1 or exceeds 21.
47       */
48      public LongFactorialEstimator(final int cacheSize) {
49          if (cacheSize < 1) {
50              throw new IllegalArgumentException("Cache size must be at least 1");
51          }
52          if (cacheSize > CACHE_SIZE) {
53              throw new IllegalArgumentException("Maximum allowed cache size is 171");
54          }
55  
56          // initialize cache
57          cache = new long[cacheSize];
58          cache[0] = 1;
59          for (var i = 1; i < cacheSize; i++) {
60              cache[i] = i * cache[i - 1];
61          }
62      }
63  
64      /**
65       * Gets current cache size.
66       *
67       * @return cache size.
68       */
69      public int getCacheSize() {
70          return cache.length;
71      }
72  
73      /**
74       * Gets factorial of provided value represented with double precision.
75       *
76       * @param value value to compute factorial for.
77       * @return computed factorial value.
78       *
79       * @throws IllegalArgumentException if provided value exceeds cache size.
80       */
81      public long factorial(final int value) {
82          if (value < 0) {
83              throw new IllegalArgumentException("Minimum supported value is 0");
84          }
85          if (value >= cache.length) {
86              throw new IllegalArgumentException("Maximum supported value is " + (cache.length - 1));
87          }
88  
89          return cache[value];
90      }
91  }