distribution 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|