1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.distribution.discrete;
23
24 import org.hipparchus.special.Gamma;
25 import org.hipparchus.util.FastMath;
26 import org.hipparchus.util.MathUtils;
27 import org.hipparchus.util.Precision;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 final class SaddlePointExpansion {
46
47
48 private static final double HALF_LOG_2_PI = 0.5 * FastMath.log(MathUtils.TWO_PI);
49
50
51 private static final double[] EXACT_STIRLING_ERRORS = {
52 0.0,
53 0.1534264097200273452913848,
54 0.0810614667953272582196702,
55 0.0548141210519176538961390,
56 0.0413406959554092940938221,
57 0.03316287351993628748511048,
58 0.02767792568499833914878929,
59 0.02374616365629749597132920,
60 0.02079067210376509311152277,
61 0.01848845053267318523077934,
62 0.01664469118982119216319487,
63 0.01513497322191737887351255,
64 0.01387612882307074799874573,
65 0.01281046524292022692424986,
66 0.01189670994589177009505572,
67 0.01110455975820691732662991,
68 0.010411265261972096497478567,
69 0.009799416126158803298389475,
70 0.009255462182712732917728637,
71 0.008768700134139385462952823,
72 0.008330563433362871256469318,
73 0.007934114564314020547248100,
74 0.007573675487951840794972024,
75 0.007244554301320383179543912,
76 0.006942840107209529865664152,
77 0.006665247032707682442354394,
78 0.006408994188004207068439631,
79 0.006171712263039457647532867,
80 0.005951370112758847735624416,
81 0.005746216513010115682023589,
82 0.005554733551962801371038690
83 };
84
85
86
87
88 private SaddlePointExpansion() {}
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 static double getStirlingError(double z) {
105 if (z < 15.0) {
106 double z2 = 2.0 * z;
107 if (Precision.isMathematicalInteger(z2)) {
108 return EXACT_STIRLING_ERRORS[(int) z2];
109 } else {
110 return Gamma.logGamma(z + 1.0) - (z + 0.5) * FastMath.log(z) +
111 z - HALF_LOG_2_PI;
112 }
113 } else {
114 double z2 = z * z;
115 return (0.083333333333333333333 -
116 (0.00277777777777777777778 -
117 (0.00079365079365079365079365 -
118 (0.000595238095238095238095238 -
119 0.0008417508417508417508417508 /
120 z2) / z2) / z2) / z2) / z;
121 }
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 static double getDeviancePart(double x, double mu) {
140 if (FastMath.abs(x - mu) < 0.1 * (x + mu)) {
141 double d = x - mu;
142 double v = d / (x + mu);
143 double s1 = v * d;
144 double s = Double.NaN;
145 double ej = 2.0 * x * v;
146 v *= v;
147 int j = 1;
148 while (s1 != s) {
149 s = s1;
150 ej *= v;
151 s1 = s + ej / ((j * 2) + 1);
152 ++j;
153 }
154 return s1;
155 } else {
156 return x * FastMath.log(x / mu) + mu - x;
157 }
158 }
159
160
161
162
163
164
165
166
167
168
169
170 static double logBinomialProbability(int x, int n, double p, double q) {
171 if (n == 0) {
172 return x == 0 ? 0d : Double.NEGATIVE_INFINITY;
173 }
174 if (x == 0) {
175 if (p < 0.1) {
176 return -getDeviancePart(n, n * q) - n * p;
177 } else {
178 return n * FastMath.log(q);
179 }
180 } else if (x == n) {
181 if (q < 0.1) {
182 return -getDeviancePart(n, n * p) - n * q;
183 } else {
184 return n * FastMath.log(p);
185 }
186 } else {
187 double ret = getStirlingError(n) - getStirlingError(x) -
188 getStirlingError(n - x) - getDeviancePart(x, n * p) -
189 getDeviancePart(n - x, n * q);
190 double f = (MathUtils.TWO_PI * x * (n - x)) / n;
191 ret = -0.5 * FastMath.log(f) + ret;
192 return ret;
193 }
194 }
195 }