distribution 0.7.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +4 -6
- data/.yardopts +5 -0
- data/History.txt +3 -0
- data/README.md +87 -44
- data/benchmark/binomial_coefficient.rb +19 -23
- data/benchmark/binomial_coefficient/experiment.rb +33 -36
- data/benchmark/factorial_hash.rb +7 -8
- data/benchmark/factorial_method.rb +4 -6
- data/benchmark/odd.rb +6 -7
- data/benchmark/power.rb +11 -11
- data/bin/distribution +26 -26
- data/distribution.gemspec +3 -4
- data/lib/distribution.rb +55 -96
- data/lib/distribution/beta/gsl.rb +10 -5
- data/lib/distribution/beta/ruby.rb +3 -1
- data/lib/distribution/binomial/ruby.rb +5 -2
- data/lib/distribution/bivariatenormal.rb +4 -5
- data/lib/distribution/bivariatenormal/gsl.rb +2 -2
- data/lib/distribution/bivariatenormal/java.rb +1 -1
- data/lib/distribution/bivariatenormal/ruby.rb +245 -254
- data/lib/distribution/chisquare.rb +8 -10
- data/lib/distribution/chisquare/gsl.rb +24 -19
- data/lib/distribution/chisquare/java.rb +1 -1
- data/lib/distribution/chisquare/ruby.rb +25 -25
- data/lib/distribution/chisquare/statistics2.rb +16 -13
- data/lib/distribution/distributable.rb +40 -0
- data/lib/distribution/exponential.rb +4 -5
- data/lib/distribution/exponential/gsl.rb +13 -9
- data/lib/distribution/exponential/ruby.rb +14 -9
- data/lib/distribution/f.rb +1 -1
- data/lib/distribution/f/gsl.rb +26 -22
- data/lib/distribution/f/java.rb +1 -1
- data/lib/distribution/f/ruby.rb +16 -19
- data/lib/distribution/f/statistics2.rb +22 -19
- data/lib/distribution/gamma.rb +5 -7
- data/lib/distribution/gamma/gsl.rb +13 -9
- data/lib/distribution/gamma/java.rb +1 -1
- data/lib/distribution/gamma/ruby.rb +5 -11
- data/lib/distribution/hypergeometric.rb +5 -8
- data/lib/distribution/hypergeometric/gsl.rb +4 -5
- data/lib/distribution/hypergeometric/java.rb +1 -1
- data/lib/distribution/hypergeometric/ruby.rb +34 -35
- data/lib/distribution/logistic.rb +5 -8
- data/lib/distribution/logistic/ruby.rb +13 -8
- data/lib/distribution/lognormal.rb +5 -7
- data/lib/distribution/lognormal/gsl.rb +8 -6
- data/lib/distribution/lognormal/ruby.rb +5 -9
- data/lib/distribution/math_extension.rb +6 -15
- data/lib/distribution/math_extension/chebyshev_series.rb +281 -272
- data/lib/distribution/math_extension/erfc.rb +26 -29
- data/lib/distribution/math_extension/exponential_integral.rb +17 -17
- data/lib/distribution/math_extension/gammastar.rb +19 -20
- data/lib/distribution/math_extension/gsl_utilities.rb +12 -12
- data/lib/distribution/math_extension/incomplete_beta.rb +52 -61
- data/lib/distribution/math_extension/incomplete_gamma.rb +166 -168
- data/lib/distribution/math_extension/log_utilities.rb +20 -22
- data/lib/distribution/normal.rb +11 -13
- data/lib/distribution/normal/gsl.rb +13 -10
- data/lib/distribution/normal/java.rb +14 -13
- data/lib/distribution/normal/ruby.rb +68 -58
- data/lib/distribution/normal/statistics2.rb +5 -2
- data/lib/distribution/normalmultivariate.rb +64 -64
- data/lib/distribution/poisson.rb +11 -13
- data/lib/distribution/poisson/gsl.rb +7 -7
- data/lib/distribution/poisson/java.rb +19 -24
- data/lib/distribution/poisson/ruby.rb +38 -9
- data/lib/distribution/shorthand.rb +17 -0
- data/lib/distribution/t.rb +13 -15
- data/lib/distribution/t/gsl.rb +27 -24
- data/lib/distribution/t/java.rb +1 -1
- data/lib/distribution/t/ruby.rb +99 -100
- data/lib/distribution/t/statistics2.rb +19 -19
- data/lib/distribution/uniform.rb +26 -0
- data/lib/distribution/uniform/gsl.rb +36 -0
- data/lib/distribution/uniform/ruby.rb +91 -0
- data/lib/distribution/version.rb +1 -1
- data/lib/distribution/weibull.rb +6 -7
- data/lib/distribution/weibull/gsl.rb +16 -16
- data/lib/distribution/weibull/ruby.rb +30 -23
- data/spec/beta_spec.rb +45 -47
- data/spec/binomial_spec.rb +77 -85
- data/spec/bivariatenormal_spec.rb +28 -35
- data/spec/chisquare_spec.rb +48 -52
- data/spec/distribution_spec.rb +10 -10
- data/spec/exponential_spec.rb +44 -49
- data/spec/f_spec.rb +4 -4
- data/spec/gamma_spec.rb +50 -53
- data/spec/hypergeometric_spec.rb +63 -69
- data/spec/logistic_spec.rb +32 -37
- data/spec/lognormal_spec.rb +25 -31
- data/spec/math_extension_spec.rb +192 -210
- data/spec/normal_spec.rb +80 -73
- data/spec/poisson_spec.rb +63 -41
- data/spec/shorthand_spec.rb +19 -22
- data/spec/spec_helper.rb +8 -9
- data/spec/t_spec.rb +63 -77
- data/spec/uniform_spec.rb +154 -0
- data/spec/weibull_spec.rb +13 -14
- metadata +17 -8
@@ -7,13 +7,12 @@ module Distribution
|
|
7
7
|
module MathExtension
|
8
8
|
module IncompleteGamma
|
9
9
|
NMAX = 5000
|
10
|
-
SMALL = Float::EPSILON
|
10
|
+
SMALL = Float::EPSILON**3
|
11
11
|
PG21 = -2.404113806319188570799476 # PolyGamma[2,1]
|
12
12
|
|
13
13
|
class << self
|
14
|
-
|
15
14
|
# Helper function for plot
|
16
|
-
#def range_to_array r
|
15
|
+
# def range_to_array r
|
17
16
|
# r << (r.last - r.first)/100.0 if r.size == 2 # set dr as Dr/100.0
|
18
17
|
# arr = []
|
19
18
|
# pos = r[0]
|
@@ -22,9 +21,9 @@ module Distribution
|
|
22
21
|
# pos += r[2]
|
23
22
|
# end
|
24
23
|
# arr
|
25
|
-
#end
|
24
|
+
# end
|
26
25
|
#
|
27
|
-
#def plot a, x_range, fun = :p
|
26
|
+
# def plot a, x_range, fun = :p
|
28
27
|
# x_range = range_to_array(x_range) if x_range.is_a?(Array)
|
29
28
|
# y_range = x_range.collect { |x| self.send(fun, a, x) }
|
30
29
|
# graph = Statsample::Graph::Scatterplot.new x_range.to_scale, y_range.to_scale
|
@@ -32,96 +31,96 @@ module Distribution
|
|
32
31
|
# f.puts(graph.to_svg)
|
33
32
|
# f.close
|
34
33
|
# `google-chrome test.svg`
|
35
|
-
#end
|
34
|
+
# end
|
36
35
|
|
37
36
|
# The dominant part, D(a,x) := x^a e^(-x) / Gamma(a+1)
|
38
37
|
# gamma_inc_D in GSL-1.9.
|
39
38
|
def d(a, x, with_error = false)
|
40
39
|
error = nil
|
41
40
|
if a < 10.0
|
42
|
-
ln_a = Math.lgamma(a+1.0).first
|
41
|
+
ln_a = Math.lgamma(a + 1.0).first
|
43
42
|
lnr = a * Math.log(x) - x - ln_a
|
44
43
|
result = Math.exp(lnr)
|
45
44
|
error = 2.0 * Float::EPSILON * (lnr.abs + 1.0) + result.abs if with_error
|
46
|
-
with_error ? [result,error] : result
|
45
|
+
with_error ? [result, error] : result
|
47
46
|
else
|
48
47
|
ln_term = ln_term_error = nil
|
49
|
-
if x < 0.5*a
|
50
|
-
u = x/a.to_f
|
48
|
+
if x < 0.5 * a
|
49
|
+
u = x / a.to_f
|
51
50
|
ln_u = Math.log(u)
|
52
51
|
ln_term = ln_u - u + 1.0
|
53
52
|
ln_term_error = (ln_u.abs + u.abs + 1.0) * Float::EPSILON if with_error
|
54
53
|
else
|
55
|
-
mu = (x-a)/a.to_f
|
56
|
-
ln_term = Log
|
54
|
+
mu = (x - a) / a.to_f
|
55
|
+
ln_term = Log.log_1plusx_minusx(mu, with_error)
|
57
56
|
ln_term, ln_term_error = ln_term if with_error
|
58
57
|
end
|
59
58
|
gstar = Gammastar.evaluate(a, with_error)
|
60
|
-
gstar,gstar_error = gstar if with_error
|
61
|
-
term1 = Math.exp(a*ln_term) / Math.sqrt(2.0*Math::PI*a)
|
62
|
-
result = term1/gstar
|
63
|
-
error = 2.0*Float::EPSILON*((a*ln_term).abs+1.0) * result.abs + gstar_error/gstar.abs * result.abs if with_error
|
64
|
-
with_error ? [result,error] : result
|
59
|
+
gstar, gstar_error = gstar if with_error
|
60
|
+
term1 = Math.exp(a * ln_term) / Math.sqrt(2.0 * Math::PI * a)
|
61
|
+
result = term1 / gstar
|
62
|
+
error = 2.0 * Float::EPSILON * ((a * ln_term).abs + 1.0) * result.abs + gstar_error / gstar.abs * result.abs if with_error
|
63
|
+
with_error ? [result, error] : result
|
65
64
|
end
|
66
65
|
end
|
67
66
|
|
68
67
|
# gamma_inc_P_series
|
69
|
-
def p_series(a,x,with_error=false)
|
70
|
-
d = d(a,x,with_error)
|
68
|
+
def p_series(a, x, with_error = false)
|
69
|
+
d = d(a, x, with_error)
|
71
70
|
d, d_err = d if with_error
|
72
71
|
sum = 1.0
|
73
72
|
term = 1.0
|
74
73
|
n = 1
|
75
|
-
1.upto(NMAX-1) do |n|
|
76
|
-
term *= x / (a+n).to_f
|
77
|
-
sum
|
78
|
-
break if (term/sum).abs < Float::EPSILON
|
74
|
+
1.upto(NMAX - 1) do |n|
|
75
|
+
term *= x / (a + n).to_f
|
76
|
+
sum += term
|
77
|
+
break if (term / sum).abs < Float::EPSILON
|
79
78
|
end
|
80
79
|
|
81
80
|
result = d * sum
|
82
81
|
|
83
82
|
if n == NMAX
|
84
|
-
STDERR.puts(
|
83
|
+
STDERR.puts('Error: n reached NMAX in p series')
|
85
84
|
else
|
86
|
-
return with_error ? [result,d_err * sum.abs + (1.0+n)*Float::EPSILON * result.abs] : result
|
85
|
+
return with_error ? [result, d_err * sum.abs + (1.0 + n) * Float::EPSILON * result.abs] : result
|
87
86
|
end
|
88
87
|
end
|
89
88
|
|
90
89
|
# This function does not exist in GSL, but is nonetheless GSL code. It's for calculating two specific ranges of p.
|
91
|
-
def q_asymptotic_uniform_complement
|
90
|
+
def q_asymptotic_uniform_complement(a, x, with_error = false)
|
92
91
|
q = q_asymptotic_uniform(a, x, with_error)
|
93
|
-
q,q_err = q if with_error
|
92
|
+
q, q_err = q if with_error
|
94
93
|
result = 1.0 - q
|
95
|
-
|
94
|
+
with_error ? [result, q_err + 2.0 * Float::EPSILON * result.abs] : result
|
96
95
|
end
|
97
96
|
|
98
|
-
def q_continued_fraction_complement
|
99
|
-
q = q_continued_fraction(a,x,with_error)
|
100
|
-
|
97
|
+
def q_continued_fraction_complement(a, x, with_error = false)
|
98
|
+
q = q_continued_fraction(a, x, with_error)
|
99
|
+
with_error ? [1.0 - q.first, q.last + 2.0 * Float::EPSILON * (1.0 - q.first).abs] : 1.0 - q
|
101
100
|
end
|
102
101
|
|
103
|
-
def q_large_x_complement
|
104
|
-
q = q_large_x(a,x,with_error)
|
105
|
-
|
102
|
+
def q_large_x_complement(a, x, with_error = false)
|
103
|
+
q = q_large_x(a, x, with_error)
|
104
|
+
with_error ? [1.0 - q.first, q.last + 2.0 * Float::EPSILON * (1.0 - q.first).abs] : 1.0 - q
|
106
105
|
end
|
107
106
|
|
108
107
|
# The incomplete gamma function.
|
109
108
|
# gsl_sf_gamma_inc_P_e
|
110
|
-
def p
|
111
|
-
|
109
|
+
def p(a, x, with_error = false)
|
110
|
+
fail(ArgumentError, 'Range Error: a must be positive, x must be non-negative') if a <= 0.0 || x < 0.0
|
112
111
|
if x == 0.0
|
113
112
|
return with_error ? [0.0, 0.0] : 0.0
|
114
|
-
elsif x < 20.0 || x < 0.5*a
|
113
|
+
elsif x < 20.0 || x < 0.5 * a
|
115
114
|
return p_series(a, x, with_error)
|
116
|
-
elsif a > 1e6 && (x-a)*(x-a) < a
|
115
|
+
elsif a > 1e6 && (x - a) * (x - a) < a
|
117
116
|
return q_asymptotic_uniform_complement a, x, with_error
|
118
117
|
elsif a <= x
|
119
|
-
if a > 0.2*x
|
118
|
+
if a > 0.2 * x
|
120
119
|
return q_continued_fraction_complement(a, x, with_error)
|
121
120
|
else
|
122
121
|
return q_large_x_complement(a, x, with_error)
|
123
122
|
end
|
124
|
-
elsif (x-a)*(x-a) < a
|
123
|
+
elsif (x - a) * (x - a) < a
|
125
124
|
return q_asymptotic_uniform_complement a, x, with_error
|
126
125
|
else
|
127
126
|
return p_series(a, x, with_error)
|
@@ -129,71 +128,71 @@ module Distribution
|
|
129
128
|
end
|
130
129
|
|
131
130
|
# gamma_inc_Q_e
|
132
|
-
def q
|
133
|
-
|
131
|
+
def q(a, x, with_error = false)
|
132
|
+
fail(ArgumentError, 'Range Error: a and x must be non-negative') if a < 0.0 || x < 0.0
|
134
133
|
if x == 0.0
|
135
134
|
return with_error ? [1.0, 0.0] : 1.0
|
136
135
|
elsif a == 0.0
|
137
136
|
return with_error ? [0.0, 0.0] : 0.0
|
138
|
-
elsif x <= 0.5*a
|
137
|
+
elsif x <= 0.5 * a
|
139
138
|
# If series is quick, do that.
|
140
|
-
p = p_series(a,x, with_error)
|
141
|
-
p,p_err = p if with_error
|
139
|
+
p = p_series(a, x, with_error)
|
140
|
+
p, p_err = p if with_error
|
142
141
|
result = 1.0 - p
|
143
|
-
return with_error ? [result, p_err + 2.0*Float::EPSILON*result.abs] : result
|
144
|
-
elsif a >= 1.0e+06 && (x-a)*(x-a) < a # difficult asymptotic regime, only way to do this region
|
142
|
+
return with_error ? [result, p_err + 2.0 * Float::EPSILON * result.abs] : result
|
143
|
+
elsif a >= 1.0e+06 && (x - a) * (x - a) < a # difficult asymptotic regime, only way to do this region
|
145
144
|
return q_asymptotic_uniform(a, x, with_error)
|
146
145
|
elsif a < 0.2 && x < 5.0
|
147
|
-
return q_series(a,x, with_error)
|
146
|
+
return q_series(a, x, with_error)
|
148
147
|
elsif a <= x
|
149
148
|
return x <= 1.0e+06 ? q_continued_fraction(a, x, with_error) : q_large_x(a, x, with_error)
|
150
149
|
else
|
151
|
-
if x > a-Math.sqrt(a)
|
150
|
+
if x > a - Math.sqrt(a)
|
152
151
|
return q_continued_fraction(a, x, with_error)
|
153
152
|
else
|
154
153
|
p = p_series(a, x, with_error)
|
155
154
|
p, p_err = p if with_error
|
156
155
|
result = 1.0 - p
|
157
|
-
return with_error ? [result, p_err + 2.0*Float::EPSILON*result.abs] : result
|
156
|
+
return with_error ? [result, p_err + 2.0 * Float::EPSILON * result.abs] : result
|
158
157
|
end
|
159
158
|
end
|
160
159
|
end
|
161
160
|
|
162
161
|
# gamma_inc_Q_CF
|
163
|
-
def q_continued_fraction
|
162
|
+
def q_continued_fraction(a, x, with_error = false)
|
164
163
|
d = d(a, x, with_error)
|
165
164
|
f = f_continued_fraction(a, x, with_error)
|
166
165
|
|
167
166
|
if with_error
|
168
|
-
[d.first*(a/x).to_f*f.first, d.last * ((a/x).to_f*f.first).abs + (d.first*a/x*f.last).abs]
|
167
|
+
[d.first * (a / x).to_f * f.first, d.last * ((a / x).to_f * f.first).abs + (d.first * a / x * f.last).abs]
|
169
168
|
else
|
170
|
-
d * (a/x).to_f * f
|
169
|
+
d * (a / x).to_f * f
|
171
170
|
end
|
172
171
|
end
|
173
172
|
|
174
173
|
# gamma_inc_Q_large_x in GSL-1.9
|
175
|
-
def q_large_x
|
176
|
-
d = d(a,x,with_error)
|
177
|
-
d,d_err = d if with_error
|
174
|
+
def q_large_x(a, x, with_error = false)
|
175
|
+
d = d(a, x, with_error)
|
176
|
+
d, d_err = d if with_error
|
178
177
|
sum = 1.0
|
179
178
|
term = 1.0
|
180
179
|
last = 1.0
|
181
180
|
n = 1
|
182
|
-
1.upto(NMAX-1).each do |n|
|
183
|
-
term *= (a-n)/x
|
184
|
-
break if (term/last).abs > 1.0
|
185
|
-
break if (term/sum).abs < Float::EPSILON
|
186
|
-
sum
|
181
|
+
1.upto(NMAX - 1).each do |n|
|
182
|
+
term *= (a - n) / x
|
183
|
+
break if (term / last).abs > 1.0
|
184
|
+
break if (term / sum).abs < Float::EPSILON
|
185
|
+
sum += term
|
187
186
|
last = term
|
188
187
|
end
|
189
188
|
|
190
|
-
result = d*(a/x)*sum
|
191
|
-
error = d_err * (a/x).abs * sum if with_error
|
189
|
+
result = d * (a / x) * sum
|
190
|
+
error = d_err * (a / x).abs * sum if with_error
|
192
191
|
|
193
192
|
if n == NMAX
|
194
|
-
STDERR.puts(
|
193
|
+
STDERR.puts('Error: n reached NMAX in q_large_x')
|
195
194
|
else
|
196
|
-
return with_error ? [result,error] : result
|
195
|
+
return with_error ? [result, error] : result
|
197
196
|
end
|
198
197
|
end
|
199
198
|
|
@@ -201,41 +200,41 @@ module Distribution
|
|
201
200
|
# gamma_inc_Q_asymp_unif
|
202
201
|
def q_asymptotic_uniform(a, x, with_error = false)
|
203
202
|
rta = Math.sqrt(a)
|
204
|
-
eps = (x-a).quo(a)
|
203
|
+
eps = (x - a).quo(a)
|
205
204
|
|
206
|
-
ln_term = Log
|
205
|
+
ln_term = Log.log_1plusx_minusx(eps, with_error)
|
207
206
|
ln_term, ln_term_err = ln_term if with_error
|
208
207
|
|
209
|
-
eta = (eps >= 0 ? 1 : -1) * Math.sqrt(-2*ln_term)
|
208
|
+
eta = (eps >= 0 ? 1 : -1) * Math.sqrt(-2 * ln_term)
|
210
209
|
|
211
|
-
erfc = Math.erfc_e(eta*rta/SQRT2, with_error)
|
210
|
+
erfc = Math.erfc_e(eta * rta / SQRT2, with_error)
|
212
211
|
erfc, erfc_err = erfc if with_error
|
213
212
|
|
214
213
|
c0 = c1 = nil
|
215
214
|
if eps.abs < ROOT5_FLOAT_EPSILON
|
216
|
-
c0 = -1.quo(3) + eps*(1.quo(12) - eps*(23.quo(540) - eps*(353.quo(
|
215
|
+
c0 = -1.quo(3) + eps * (1.quo(12) - eps * (23.quo(540) - eps * (353.quo(12_960) - eps * 589.quo(30_240))))
|
217
216
|
c1 = -1.quo(540) - eps.quo(288)
|
218
217
|
else
|
219
|
-
rt_term = Math.sqrt(-2 * ln_term.quo(eps*eps))
|
218
|
+
rt_term = Math.sqrt(-2 * ln_term.quo(eps * eps))
|
220
219
|
lam = x.quo(a)
|
221
|
-
c0 = (1 - 1/rt_term)/eps
|
222
|
-
c1 = -(eta**3 * (lam*lam + 10*lam + 1) - 12*eps**3).quo(12 * eta**3 * eps**3)
|
220
|
+
c0 = (1 - 1 / rt_term) / eps
|
221
|
+
c1 = -(eta**3 * (lam * lam + 10 * lam + 1) - 12 * eps**3).quo(12 * eta**3 * eps**3)
|
223
222
|
end
|
224
223
|
|
225
|
-
r = Math.exp(-0.5*a*eta*eta) / (SQRT2*SQRTPI*rta) * (c0 + c1.quo(a))
|
224
|
+
r = Math.exp(-0.5 * a * eta * eta) / (SQRT2 * SQRTPI * rta) * (c0 + c1.quo(a))
|
226
225
|
|
227
226
|
result = 0.5 * erfc + r
|
228
|
-
with_error ? [result, Float::EPSILON + (r*0.5*a*eta*eta).abs + 0.5*erfc_err + 2.0*Float::EPSILON + result.abs] : result
|
227
|
+
with_error ? [result, Float::EPSILON + (r * 0.5 * a * eta * eta).abs + 0.5 * erfc_err + 2.0 * Float::EPSILON + result.abs] : result
|
229
228
|
end
|
230
229
|
|
231
230
|
# gamma_inc_F_CF
|
232
|
-
def f_continued_fraction
|
231
|
+
def f_continued_fraction(a, x, with_error = false)
|
233
232
|
hn = 1.0 # convergent
|
234
233
|
cn = 1.0 / SMALL
|
235
234
|
dn = 1.0
|
236
235
|
n = 2
|
237
|
-
2.upto(NMAX-1).each do |n|
|
238
|
-
an = n.odd? ? 0.5*(n-1)/x : (0.5*n-a)/x
|
236
|
+
2.upto(NMAX - 1).each do |n|
|
237
|
+
an = n.odd? ? 0.5 * (n - 1) / x : (0.5 * n - a) / x
|
239
238
|
dn = 1.0 + an * dn
|
240
239
|
dn = SMALL if dn.abs < SMALL
|
241
240
|
cn = 1.0 + an / cn
|
@@ -243,17 +242,17 @@ module Distribution
|
|
243
242
|
dn = 1.0 / dn
|
244
243
|
delta = cn * dn
|
245
244
|
hn *= delta
|
246
|
-
break if (delta-1.0).abs < Float::EPSILON
|
245
|
+
break if (delta - 1.0).abs < Float::EPSILON
|
247
246
|
end
|
248
247
|
|
249
248
|
if n == NMAX
|
250
|
-
STDERR.puts(
|
249
|
+
STDERR.puts('Error: n reached NMAX in f continued fraction')
|
251
250
|
else
|
252
|
-
with_error ? [hn,2.0*Float::EPSILON * hn.abs + Float::EPSILON*(2.0+0.5*n) * hn.abs] : hn
|
251
|
+
with_error ? [hn, 2.0 * Float::EPSILON * hn.abs + Float::EPSILON * (2.0 + 0.5 * n) * hn.abs] : hn
|
253
252
|
end
|
254
253
|
end
|
255
254
|
|
256
|
-
def q_series(a,x,with_error=false)
|
255
|
+
def q_series(a, x, with_error = false)
|
257
256
|
term1 = nil
|
258
257
|
sum = nil
|
259
258
|
term2 = nil
|
@@ -261,120 +260,120 @@ module Distribution
|
|
261
260
|
lnx = Math.log(x)
|
262
261
|
el = EULER + lnx
|
263
262
|
c1 = -el
|
264
|
-
c2 = Math::PI * Math::PI / 12.0 - 0.5*el*el
|
265
|
-
c3 = el*(Math::PI*Math::PI/12.0 - el*el/6.0) + PG21/6.0
|
263
|
+
c2 = Math::PI * Math::PI / 12.0 - 0.5 * el * el
|
264
|
+
c3 = el * (Math::PI * Math::PI / 12.0 - el * el / 6.0) + PG21 / 6.0
|
266
265
|
c4 = -0.04166666666666666667 *
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
266
|
+
(-1.758243446661483480 + lnx) *
|
267
|
+
(-0.764428657272716373 + lnx) *
|
268
|
+
(0.723980571623507657 + lnx) *
|
269
|
+
(4.107554191916823640 + lnx)
|
271
270
|
c5 = -0.0083333333333333333 *
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
271
|
+
(-2.06563396085715900 + lnx) *
|
272
|
+
(-1.28459889470864700 + lnx) *
|
273
|
+
(-0.27583535756454143 + lnx) *
|
274
|
+
(1.33677371336239618 + lnx) *
|
275
|
+
(5.17537282427561550 + lnx)
|
277
276
|
c6 = -0.0013888888888888889 *
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
277
|
+
(-2.30814336454783200 + lnx) *
|
278
|
+
(-1.65846557706987300 + lnx) *
|
279
|
+
(-0.88768082560020400 + lnx) *
|
280
|
+
(0.17043847751371778 + lnx) *
|
281
|
+
(1.92135970115863890 + lnx) *
|
282
|
+
(6.22578557795474900 + lnx)
|
284
283
|
c7 = -0.00019841269841269841
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
284
|
+
(-2.5078657901291800 + lnx) *
|
285
|
+
(-1.9478900888958200 + lnx) *
|
286
|
+
(-1.3194837322612730 + lnx) *
|
287
|
+
(-0.5281322700249279 + lnx) *
|
288
|
+
(0.5913834939078759 + lnx) *
|
289
|
+
(2.4876819633378140 + lnx) *
|
290
|
+
(7.2648160783762400 + lnx)
|
292
291
|
c8 = -0.00002480158730158730 *
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
term1 = a*(c1+a*(c2+a*(c3+a*(c4+a*(c5+a*(c6+a*(c7+a*(c8+a*(c9+a*c10)))))))))
|
292
|
+
(-2.677341544966400 + lnx) *
|
293
|
+
(-2.182810448271700 + lnx) *
|
294
|
+
(-1.649350342277400 + lnx) *
|
295
|
+
(-1.014099048290790 + lnx) *
|
296
|
+
(-0.191366955370652 + lnx) *
|
297
|
+
(0.995403817918724 + lnx) *
|
298
|
+
(3.041323283529310 + lnx) *
|
299
|
+
(8.295966556941250 + lnx) *
|
300
|
+
c9 = -2.75573192239859e-6 *
|
301
|
+
(-2.8243487670469080 + lnx) *
|
302
|
+
(-2.3798494322701120 + lnx) *
|
303
|
+
(-1.9143674728689960 + lnx) *
|
304
|
+
(-1.3814529102920370 + lnx) *
|
305
|
+
(-0.7294312810261694 + lnx) *
|
306
|
+
(0.1299079285269565 + lnx) *
|
307
|
+
(1.3873333251885240 + lnx) *
|
308
|
+
(3.5857258865210760 + lnx) *
|
309
|
+
(9.3214237073814600 + lnx) *
|
310
|
+
c10 = -2.75573192239859e-7 *
|
311
|
+
(-2.9540329644556910 + lnx) *
|
312
|
+
(-2.5491366926991850 + lnx) *
|
313
|
+
(-2.1348279229279880 + lnx) *
|
314
|
+
(-1.6741881076349450 + lnx) *
|
315
|
+
(-1.1325949616098420 + lnx) *
|
316
|
+
(-0.4590034650618494 + lnx) *
|
317
|
+
(0.4399352987435699 + lnx) *
|
318
|
+
(1.7702236517651670 + lnx) *
|
319
|
+
(4.1231539047474080 + lnx) *
|
320
|
+
(10.342627908148680 + lnx)
|
321
|
+
term1 = a * (c1 + a * (c2 + a * (c3 + a * (c4 + a * (c5 + a * (c6 + a * (c7 + a * (c8 + a * (c9 + a * c10)))))))))
|
323
322
|
end
|
324
323
|
|
325
324
|
n = 1
|
326
325
|
begin
|
327
326
|
t = 1.0
|
328
327
|
sum = 1.0
|
329
|
-
1.upto(NMAX-1).each do |n|
|
330
|
-
t
|
331
|
-
sum += (a+1.0) / (a+n+1.0) * t
|
332
|
-
break if (t/sum).abs < Float::EPSILON
|
328
|
+
1.upto(NMAX - 1).each do |n|
|
329
|
+
t *= -x / (n + 1.0)
|
330
|
+
sum += (a + 1.0) / (a + n + 1.0) * t
|
331
|
+
break if (t / sum).abs < Float::EPSILON
|
333
332
|
end
|
334
333
|
end
|
335
334
|
|
336
335
|
if n == NMAX
|
337
|
-
STDERR.puts(
|
336
|
+
STDERR.puts('Error: n reached NMAX in q_series')
|
338
337
|
else
|
339
|
-
term2 = (1.0 - term1) * a/(a+1.0) * x * sum
|
340
|
-
result = term1+term2
|
341
|
-
with_error ? [result, Float::EPSILON*term1.abs + 2.0*term2.abs + 2.0*Float::EPSILON*result.abs] : result
|
338
|
+
term2 = (1.0 - term1) * a / (a + 1.0) * x * sum
|
339
|
+
result = term1 + term2
|
340
|
+
with_error ? [result, Float::EPSILON * term1.abs + 2.0 * term2.abs + 2.0 * Float::EPSILON * result.abs] : result
|
342
341
|
end
|
343
342
|
end
|
344
343
|
|
345
344
|
# gamma_inc_series
|
346
|
-
def series
|
347
|
-
q = q_series(a,x,with_error)
|
345
|
+
def series(a, x, with_error = false)
|
346
|
+
q = q_series(a, x, with_error)
|
348
347
|
g = Math.gamma(a)
|
349
348
|
STDERR.puts("Warning: Don't know error for Math.gamma. Error will be incorrect") if with_error
|
350
349
|
# When we get the error from Gamma, switch the comment on the next to lines
|
351
350
|
# with_error ? [q.first*g.first, (q.first*g.last).abs + (q.last*g.first).abs + 2.0*Float::EPSILON*(q.first*g.first).abs] : q*g
|
352
|
-
with_error ? [q.first*g, (q.first*Float::EPSILON).abs + (q.last*g.first).abs + 2.0*Float::EPSILON(q.first*g).abs] : q*g
|
351
|
+
with_error ? [q.first * g, (q.first * Float::EPSILON).abs + (q.last * g.first).abs + 2.0 * Float::EPSILON(q.first * g).abs] : q * g
|
353
352
|
end
|
354
353
|
|
355
354
|
# gamma_inc_a_gt_0
|
356
|
-
def a_greater_than_0
|
357
|
-
q = q(a,x,with_error)
|
358
|
-
q,q_err = q if with_error
|
355
|
+
def a_greater_than_0(a, x, with_error = false)
|
356
|
+
q = q(a, x, with_error)
|
357
|
+
q, q_err = q if with_error
|
359
358
|
g = Math.gamma(a)
|
360
359
|
STDERR.puts("Warning: Don't know error for Math.gamma. Error will be incorrect") if with_error
|
361
360
|
g_err = Float::EPSILON
|
362
|
-
result = g*q
|
363
|
-
error = (g*q_err).abs + (g_err*q).abs if with_error
|
364
|
-
with_error ? [result,error] : result
|
361
|
+
result = g * q
|
362
|
+
error = (g * q_err).abs + (g_err * q).abs if with_error
|
363
|
+
with_error ? [result, error] : result
|
365
364
|
end
|
366
365
|
|
367
366
|
# gamma_inc_CF
|
368
|
-
def continued_fraction
|
369
|
-
f = f_continued_fraction(a,x,with_error)
|
370
|
-
f,f_error = f if with_error
|
371
|
-
pre = Math.exp((a-1.0)*Math.log(x) - x)
|
367
|
+
def continued_fraction(a, x, with_error = false)
|
368
|
+
f = f_continued_fraction(a, x, with_error)
|
369
|
+
f, f_error = f if with_error
|
370
|
+
pre = Math.exp((a - 1.0) * Math.log(x) - x)
|
372
371
|
STDERR.puts("Warning: Don't know error for Math.exp. Error will be incorrect") if with_error
|
373
372
|
pre_error = Float::EPSILON
|
374
|
-
result = f*pre
|
373
|
+
result = f * pre
|
375
374
|
if with_error
|
376
|
-
error = (f_error*pre).abs + (f*pre_error) + (2.0+a.abs)*Float::EPSILON*result.abs
|
377
|
-
[result,error]
|
375
|
+
error = (f_error * pre).abs + (f * pre_error) + (2.0 + a.abs) * Float::EPSILON * result.abs
|
376
|
+
[result, error]
|
378
377
|
else
|
379
378
|
result
|
380
379
|
end
|
@@ -382,8 +381,8 @@ module Distribution
|
|
382
381
|
|
383
382
|
# Unnormalized incomplete gamma function.
|
384
383
|
# gsl_sf_gamma_inc_e
|
385
|
-
def unnormalized
|
386
|
-
|
384
|
+
def unnormalized(a, x, with_error = false)
|
385
|
+
fail(ArgumentError, 'x cannot be negative') if x < 0.0
|
387
386
|
|
388
387
|
if x == 0.0
|
389
388
|
result = Math.gamma(a.to_f)
|
@@ -397,7 +396,7 @@ module Distribution
|
|
397
396
|
# continued fraction seems to fail for x too small
|
398
397
|
return continued_fraction(a.to_f, x.to_f, with_error)
|
399
398
|
elsif a.abs < 0.5
|
400
|
-
return series(a.to_f,x.to_f,with_error)
|
399
|
+
return series(a.to_f, x.to_f, with_error)
|
401
400
|
else
|
402
401
|
fa = a.floor.to_f
|
403
402
|
da = a - fa
|
@@ -408,17 +407,16 @@ module Distribution
|
|
408
407
|
|
409
408
|
# Gamma(alpha-1,x) = 1/(alpha-1) (Gamma(a,x) - x^(alpha-1) e^-x)
|
410
409
|
begin
|
411
|
-
shift = Math.exp(-x + (alpha-1.0)*Math.log(x))
|
412
|
-
gax = (gax-shift) / (alpha-1.0)
|
410
|
+
shift = Math.exp(-x + (alpha - 1.0) * Math.log(x))
|
411
|
+
gax = (gax - shift) / (alpha - 1.0)
|
413
412
|
alpha -= 1.0
|
414
413
|
end while alpha > a
|
415
414
|
|
416
415
|
result = gax
|
417
|
-
return with_error ? [result, 2.0*(1.0 + a.abs) * Float::EPSILON*gax.abs] : result
|
416
|
+
return with_error ? [result, 2.0 * (1.0 + a.abs) * Float::EPSILON * gax.abs] : result
|
418
417
|
end
|
419
418
|
end
|
420
|
-
|
421
419
|
end
|
422
420
|
end
|
423
421
|
end
|
424
|
-
end
|
422
|
+
end
|