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.statistics.distribution;
18  
19  /**
20   * Utility class used by various distributions to accurately compute their
21   * respective probability mass functions. The implementation for this class is
22   * based on the Catherine Loader's
23   * <a href="http://www.herine.net/stat/software/dbinom.html">dbinom</a> routines.
24   *
25   * This class is not intended to be called directly.
26   */
27  final class SaddlePointExpansionUtils {
28      /** 2 &pi;. */
29      private static final double TWO_PI = 2 * Math.PI;
30      /** 1/10. */
31      private static final double ONE_TENTH = 0.1;
32      /** The threshold value for switching the method to compute th Stirling error. */
33      private static final int STIRLING_ERROR_THRESHOLD = 15;
34  
35      /** Exact Stirling expansion error for certain values. */
36      private static final double[] EXACT_STIRLING_ERRORS = {
37          0.0, /* 0.0 */
38          0.1534264097200273452913848, /* 0.5 */
39          0.0810614667953272582196702, /* 1.0 */
40          0.0548141210519176538961390, /* 1.5 */
41          0.0413406959554092940938221, /* 2.0 */
42          0.03316287351993628748511048, /* 2.5 */
43          0.02767792568499833914878929, /* 3.0 */
44          0.02374616365629749597132920, /* 3.5 */
45          0.02079067210376509311152277, /* 4.0 */
46          0.01848845053267318523077934, /* 4.5 */
47          0.01664469118982119216319487, /* 5.0 */
48          0.01513497322191737887351255, /* 5.5 */
49          0.01387612882307074799874573, /* 6.0 */
50          0.01281046524292022692424986, /* 6.5 */
51          0.01189670994589177009505572, /* 7.0 */
52          0.01110455975820691732662991, /* 7.5 */
53          0.010411265261972096497478567, /* 8.0 */
54          0.009799416126158803298389475, /* 8.5 */
55          0.009255462182712732917728637, /* 9.0 */
56          0.008768700134139385462952823, /* 9.5 */
57          0.008330563433362871256469318, /* 10.0 */
58          0.007934114564314020547248100, /* 10.5 */
59          0.007573675487951840794972024, /* 11.0 */
60          0.007244554301320383179543912, /* 11.5 */
61          0.006942840107209529865664152, /* 12.0 */
62          0.006665247032707682442354394, /* 12.5 */
63          0.006408994188004207068439631, /* 13.0 */
64          0.006171712263039457647532867, /* 13.5 */
65          0.005951370112758847735624416, /* 14.0 */
66          0.005746216513010115682023589, /* 14.5 */
67          0.005554733551962801371038690 /* 15.0 */
68      };
69  
70      /**
71       * Forbid construction.
72       */
73      private SaddlePointExpansionUtils() {}
74  
75      /**
76       * Compute the error of Stirling's series at the given value.
77       * <p>
78       * References:
79       * <ol>
80       * <li>Eric W. Weisstein. "Stirling's Series." From MathWorld--A Wolfram Web
81       * Resource. <a target="_blank"
82       * href="https://mathworld.wolfram.com/StirlingsSeries.html">
83       * https://mathworld.wolfram.com/StirlingsSeries.html</a></li>
84       * </ol>
85       * </p>
86       *
87       * <p>Note: This function has been modified for integer {@code z}.</p>
88       *
89       * @param z Value at which the function is evaluated.
90       * @return the Stirling's series error.
91       */
92      static double getStirlingError(int z) {
93          if (z <= STIRLING_ERROR_THRESHOLD) {
94              return EXACT_STIRLING_ERRORS[2 * z];
95          }
96          final double z2 = (double) z * z;
97          return (0.083333333333333333333 -
98                         (0.00277777777777777777778 -
99                                 (0.00079365079365079365079365 -
100                                        (0.000595238095238095238095238 -
101                                                0.0008417508417508417508417508 /
102                                                z2) / z2) / z2) / z2) / z;
103     }
104 
105     /**
106      * A part of the deviance portion of the saddle point approximation.
107      * <p>
108      * References:
109      * <ol>
110      * <li>Catherine Loader (2000). "Fast and Accurate Computation of Binomial
111      * Probabilities.". <a target="_blank"
112      * href="http://www.herine.net/stat/papers/dbinom.pdf">
113      * http://www.herine.net/stat/papers/dbinom.pdf</a></li>
114      * </ol>
115      * </p>
116      *
117      * <p>Note: This function has been modified for integer {@code x}.</p>
118      *
119      * @param x Value at which the function is evaluated.
120      * @param mu Average.
121      * @return a part of the deviance.
122      */
123     static double getDeviancePart(int x, double mu) {
124         if (Math.abs(x - mu) < 0.1 * (x + mu)) {
125             final double d = x - mu;
126             double v = d / (x + mu);
127             double s1 = v * d;
128             double s = Double.NaN;
129             double ej = 2.0 * x * v;
130             v *= v;
131             int j = 1;
132             while (s1 != s) {
133                 s = s1;
134                 ej *= v;
135                 s1 = s + ej / ((j * 2) + 1);
136                 ++j;
137             }
138             return s1;
139         } else if (x == 0) {
140             return mu;
141         }
142         return x * Math.log(x / mu) + mu - x;
143     }
144 
145     /**
146      * Compute the logarithm of the PMF for a binomial distribution
147      * using the saddle point expansion.
148      *
149      * @param x Value at which the probability is evaluated.
150      * @param n Number of trials.
151      * @param p Probability of success.
152      * @param q Probability of failure (1 - p).
153      * @return log(p(x)).
154      */
155     static double logBinomialProbability(int x, int n, double p, double q) {
156         if (x == 0) {
157             if (p < ONE_TENTH) {
158                 // Subtract from 0 avoids returning -0.0 for p=0.0
159                 return 0.0 - getDeviancePart(n, n * q) - n * p;
160             } else if (n == 0) {
161                 return 0;
162             }
163             return n * Math.log(q);
164         } else if (x == n) {
165             if (q < ONE_TENTH) {
166                 // Subtract from 0 avoids returning -0.0 for p=1.0
167                 return 0.0 - getDeviancePart(n, n * p) - n * q;
168             }
169             return n * Math.log(p);
170         }
171         final int nMx = n - x;
172         final double ret = getStirlingError(n) - getStirlingError(x) -
173                            getStirlingError(nMx) - getDeviancePart(x, n * p) -
174                            getDeviancePart(nMx, n * q);
175         final double f = (TWO_PI * x * nMx) / n;
176         return -0.5 * Math.log(f) + ret;
177     }
178 }