rubystats 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,171 @@
1
+ #! /usr/local/bin/ruby
2
+
3
+ # Fisher's Exact Test Function Library
4
+ #
5
+ # Based on JavaScript version created by: Oyvind Langsrud
6
+ # Ported to Ruby by Bryan Donovan
7
+ module Rubystats
8
+ class FishersExactTest
9
+
10
+ def initialize
11
+ @sn11 = 0.0
12
+ @sn1_ = 0.0
13
+ @sn_1 = 0.0
14
+ @sn = 0.0
15
+ @sprob = 0.0
16
+
17
+ @sleft = 0.0
18
+ @sright = 0.0
19
+ @sless = 0.0
20
+ @slarg = 0.0
21
+
22
+ @left = 0.0
23
+ @right = 0.0
24
+ @twotail = 0.0
25
+ end
26
+
27
+ # Reference: "Lanczos, C. 'A precision approximation
28
+ # of the gamma function', J. SIAM Numer. Anal., B, 1, 86-96, 1964."
29
+ # Translation of Alan Miller's FORTRAN-implementation
30
+ # See http://lib.stat.cmu.edu/apstat/245
31
+ def lngamm(z)
32
+ x = 0
33
+ x += 0.0000001659470187408462/(z+7)
34
+ x += 0.000009934937113930748 /(z+6)
35
+ x -= 0.1385710331296526 /(z+5)
36
+ x += 12.50734324009056 /(z+4)
37
+ x -= 176.6150291498386 /(z+3)
38
+ x += 771.3234287757674 /(z+2)
39
+ x -= 1259.139216722289 /(z+1)
40
+ x += 676.5203681218835 /(z)
41
+ x += 0.9999999999995183
42
+
43
+ return(Math.log(x)-5.58106146679532777-z+(z-0.5) * Math.log(z+6.5))
44
+ end
45
+
46
+ def lnfact(n)
47
+ if n <= 1
48
+ return 0
49
+ else
50
+ return lngamm(n+1)
51
+ end
52
+ end
53
+
54
+ def lnbico(n,k)
55
+ return lnfact(n) - lnfact(k) - lnfact(n-k)
56
+ end
57
+
58
+ def hyper_323(n11, n1_, n_1, n)
59
+ return Math.exp(lnbico(n1_, n11) + lnbico(n-n1_, n_1-n11) - lnbico(n, n_1))
60
+ end
61
+
62
+ def hyper(n11)
63
+ return hyper0(n11, 0, 0, 0)
64
+ end
65
+
66
+ def hyper0(n11i,n1_i,n_1i,ni)
67
+ if n1_i == 0 and n_1i ==0 and ni == 0
68
+ unless n11i % 10 == 0
69
+ if n11i == @sn11+1
70
+ @sprob *= ((@sn1_ - @sn11)/(n11i.to_f))*((@sn_1 - @sn11)/(n11i.to_f + @sn - @sn1_ - @sn_1))
71
+ @sn11 = n11i
72
+ return @sprob
73
+ end
74
+ if n11i == @sn11-1
75
+ @sprob *= ((@sn11)/(@sn1_-n11i.to_f))*((@sn11+@sn-@sn1_-@sn_1)/(@sn_1-n11i.to_f))
76
+ @sn11 = n11i
77
+ return @sprob
78
+ end
79
+ end
80
+ @sn11 = n11i
81
+ else
82
+ @sn11 = n11i
83
+ @sn1_ = n1_i
84
+ @sn_1 = n_1i
85
+ @sn = ni
86
+ end
87
+ @sprob = hyper_323(@sn11,@sn1_,@sn_1,@sn)
88
+ return @sprob
89
+ end
90
+
91
+ def exact(n11,n1_,n_1,n)
92
+
93
+ p = i = j = prob = 0.0
94
+
95
+ max = n1_
96
+ max = n_1 if n_1 < max
97
+ min = n1_ + n_1 - n
98
+ min = 0 if min < 0
99
+
100
+ if min == max
101
+ @sless = 1
102
+ @sright = 1
103
+ @sleft = 1
104
+ @slarg = 1
105
+ return 1
106
+ end
107
+
108
+ prob = hyper0(n11,n1_,n_1,n)
109
+ @sleft = 0
110
+
111
+ p = hyper(min)
112
+ i = min + 1
113
+ while p < (0.99999999 * prob)
114
+ @sleft += p
115
+ p = hyper(i)
116
+ i += 1
117
+ end
118
+
119
+ i -= 1
120
+
121
+ if p < (1.00000001*prob)
122
+ @sleft += p
123
+ else
124
+ i -= 1
125
+ end
126
+
127
+ @sright = 0
128
+
129
+ p = hyper(max)
130
+ j = max - 1
131
+ while p < (0.99999999 * prob)
132
+ @sright += p
133
+ p = hyper(j)
134
+ j -= 1
135
+ end
136
+ j += 1
137
+
138
+ if p < (1.00000001*prob)
139
+ @sright += p
140
+ else
141
+ j += 1
142
+ end
143
+
144
+ if (i - n11).abs < (j - n11).abs
145
+ @sless = @sleft
146
+ @slarg = 1 - @sleft + prob
147
+ else
148
+ @sless = 1 - @sright + prob
149
+ @slarg = @sright
150
+ end
151
+ return prob
152
+ end
153
+
154
+ def calculate(n11_,n12_,n21_,n22_)
155
+ n11_ *= -1 if n11_ < 0
156
+ n12_ *= -1 if n12_ < 0
157
+ n21_ *= -1 if n21_ < 0
158
+ n22_ *= -1 if n22_ < 0
159
+ n1_ = n11_ + n12_
160
+ n_1 = n11_ + n21_
161
+ n = n11_ + n12_ + n21_ + n22_
162
+ prob = exact(n11_,n1_,n_1,n)
163
+ left = @sless
164
+ right = @slarg
165
+ twotail = @sleft + @sright
166
+ twotail = 1 if twotail > 1
167
+ values_hash = { :left =>left, :right =>right, :twotail =>twotail }
168
+ return values_hash
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,742 @@
1
+ module Rubystats
2
+
3
+ module ExtraMath
4
+ def binomial (n, k)
5
+ return Math.exp(log_gamma(n + 1.0) - log_gamma(k + 1.0) - log_gamma(n - k + 1.0))
6
+ end
7
+ end
8
+
9
+ module NumericalConstants
10
+ Max_float = 3.40282346638528860e292
11
+ Eps = 2.22e-16
12
+ Max_value = 1.2e290
13
+ Log_gamma_x_max_value = 2.55e292
14
+ Gamma_x_max_value = 171.624
15
+ Sqrt2pi = 2.5066282746310005024157652848110452530069867406099
16
+ Sqrt2 = 1.4142135623730950488016887242096980785696718753769
17
+ Xminin = 2.23e-303
18
+ Max_iterations = 1000
19
+ Precision = 8.88e-016
20
+ Two_pi = 6.2831853071795864769252867665590057683943387987502
21
+ Gamma = 0.57721566490153286060651209008240243104215933593992
22
+ Golden_ratio = 1.6180339887498948482045868343656381177203091798058
23
+ end
24
+
25
+
26
+ # Ruby port of SpecialMath.php from PHPMath, which is
27
+ # a port of JSci methods found in SpecialMath.java.
28
+ #
29
+ #
30
+ # Ruby port by Bryan Donovan bryandonovan.com
31
+ #
32
+ # Author:: Jaco van Kooten
33
+ # Author:: Paul Meagher
34
+ # Author:: Bryan Donovan
35
+ module SpecialMath
36
+
37
+ include Rubystats::NumericalConstants
38
+
39
+ @logGammaCache_res = 0.0
40
+ @logGammaCache_x = 0.0
41
+ @logBetaCache_res = 0.0
42
+ @logBetaCache_p = 0.0
43
+ @logBetaCache_q = 0.0
44
+
45
+ def log_beta(p,q)
46
+ if p != @logBetaCache_p || q != @logBetaCache_q
47
+ logBetaCache_p = p
48
+ logBetaCache_q = q
49
+ if p <= 0.0 || q <= 0.0 || (p + q) > Log_gamma_x_max_value
50
+ logBetaCache_res = 0.0
51
+ else
52
+ logBetaCache_res = log_gamma(p) + log_gamma(q) - log_gamma(p + q)
53
+ end
54
+ return logBetaCache_res
55
+ end
56
+ end
57
+
58
+ # Gamma function.
59
+ # Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz<BR>
60
+ # Applied Mathematics Division<BR>
61
+ # Argonne National Laboratory<BR>
62
+ # Argonne, IL 60439<BR>
63
+ # <P>
64
+ # References:
65
+ # <OL>
66
+ # <LI>"An Overview of Software Development for Special Functions", W. J. Cody, Lecture Notes in Mathematics, 506, Numerical Analysis Dundee, 1975, G. A. Watson (ed.), Springer Verlag, Berlin, 1976.
67
+ # <LI>Computer Approximations, Hart, Et. Al., Wiley and sons, New York, 1968.
68
+ # </OL></P><P>
69
+ # From the original documentation:
70
+ # </P><P>
71
+ # This routine calculates the GAMMA function for a real argument X.
72
+ # Computation is based on an algorithm outlined in reference 1.
73
+ # The program uses rational functions that approximate the GAMMA
74
+ # function to at least 20 significant decimal digits. Coefficients
75
+ # for the approximation over the interval (1,2) are unpublished.
76
+ # Those for the approximation for X .GE. 12 are from reference 2.
77
+ # The accuracy achieved depends on the arithmetic system, the
78
+ # compiler, the intrinsic functions, and proper selection of the
79
+ # machine-dependent constants.
80
+ # </P><P>
81
+ # Error returns:<BR>
82
+ # The program returns the value XINF for singularities or when overflow would occur.
83
+ # The computation is believed to be free of underflow and overflow.
84
+ # </P>
85
+ # Author:: Jaco van Kooten
86
+
87
+ def gamma(x)
88
+ # gamma related constants
89
+ g_p = [ -1.71618513886549492533811, 24.7656508055759199108314,
90
+ -379.804256470945635097577, 629.331155312818442661052,
91
+ 866.966202790413211295064, -31451.2729688483675254357,
92
+ -36144.4134186911729807069, 66456.1438202405440627855 ]
93
+ g_q = [-30.8402300119738975254353, 315.350626979604161529144,
94
+ -1015.15636749021914166146, -3107.77167157231109440444,
95
+ 22538.1184209801510330112, 4755.84627752788110767815,
96
+ -134659.959864969306392456, -115132.259675553483497211 ]
97
+ g_c = [-0.001910444077728, 8.4171387781295e-4, -5.952379913043012e-4,
98
+ 7.93650793500350248e-4, -0.002777777777777681622553,
99
+ 0.08333333333333333331554247, 0.0057083835261 ]
100
+ fact=1.0
101
+ i=0
102
+ n=0
103
+ y=x
104
+ parity=false
105
+ if y <= 0.0
106
+ # ----------------------------------------------------------------------
107
+ # Argument is negative
108
+ # ----------------------------------------------------------------------
109
+ y = -(x)
110
+ y1 = y.to_i
111
+ res = y - y1
112
+ if res != 0.0
113
+ if y1 != (((y1*0.5).to_i) * 2.0)
114
+ parity = true
115
+ fact = -M_pi/sin(M_pi * res)
116
+ y += 1
117
+ end
118
+ else
119
+ return Max_value
120
+ end
121
+ end
122
+
123
+ # ----------------------------------------------------------------------
124
+ # Argument is positive
125
+ # ----------------------------------------------------------------------
126
+ if y < Eps
127
+ # ----------------------------------------------------------------------
128
+ # Argument .LT. EPS
129
+ # ----------------------------------------------------------------------
130
+ if y >= Xminin
131
+ res = 1.0 / y
132
+ else
133
+ return Max_value
134
+ end
135
+ elsif y < 12.0
136
+ y1 = y
137
+ #end
138
+ if y < 1.0
139
+ # ----------------------------------------------------------------------
140
+ # 0.0 .LT. argument .LT. 1.0
141
+ # ----------------------------------------------------------------------
142
+ z = y
143
+ y += 1
144
+ else
145
+ # ----------------------------------------------------------------------
146
+ # 1.0 .LT. argument .LT. 12.0, reduce argument if necessary
147
+ # ----------------------------------------------------------------------
148
+ n = y.to_i - 1
149
+ y -= n.to_f
150
+ z = y - 1.0
151
+ end
152
+ # ----------------------------------------------------------------------
153
+ # Evaluate approximation for 1.0 .LT. argument .LT. 2.0
154
+ # ----------------------------------------------------------------------
155
+ xnum = 0.0
156
+ xden = 1.0
157
+ for i in (0...8)
158
+ xnum = (xnum + g_p[i]) * z
159
+ xden = xden * z + g_q[i]
160
+ end
161
+ res = xnum / xden + 1.0
162
+ if y1 < y
163
+ # ----------------------------------------------------------------------
164
+ # Adjust result for case 0.0 .LT. argument .LT. 1.0
165
+ # ----------------------------------------------------------------------
166
+ res /= y1
167
+ elsif y1 > y
168
+ # ----------------------------------------------------------------------
169
+ # Adjust result for case 2.0 .LT. argument .LT. 12.0
170
+ # ----------------------------------------------------------------------
171
+ for i in (0...n)
172
+ res *= y
173
+ y += 1
174
+ end
175
+ end
176
+ else
177
+ # ----------------------------------------------------------------------
178
+ # Evaluate for argument .GE. 12.0
179
+ # ----------------------------------------------------------------------
180
+ if y <= Gamma_x_max_value
181
+ ysq = y * y
182
+ sum = g_c[6]
183
+ for i in(0...6)
184
+ sum = sum / ysq + g_c[i]
185
+ sum = sum / y - y + log(sqrt2pi)
186
+ sum += (y - 0.5) * log(y)
187
+ res = Math.exp(sum)
188
+ end
189
+ else
190
+ return Max_value
191
+ end
192
+ # ----------------------------------------------------------------------
193
+ # Final adjustments and return
194
+ # ----------------------------------------------------------------------
195
+ if parity
196
+ res = -res
197
+ if fact != 1.0
198
+ res = fact / res
199
+ return res
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ def log_gamma(x)
206
+ logGammaCache_res = @logGammaCache_res
207
+ logGammaCache_x = @logGammaCache_x
208
+
209
+ lg_d1 = -0.5772156649015328605195174
210
+ lg_d2 = 0.4227843350984671393993777
211
+ lg_d4 = 1.791759469228055000094023
212
+
213
+ lg_p1 = [ 4.945235359296727046734888,
214
+ 201.8112620856775083915565, 2290.838373831346393026739,
215
+ 11319.67205903380828685045, 28557.24635671635335736389,
216
+ 38484.96228443793359990269, 26377.48787624195437963534,
217
+ 7225.813979700288197698961 ]
218
+
219
+ lg_p2 = [ 4.974607845568932035012064,
220
+ 542.4138599891070494101986, 15506.93864978364947665077,
221
+ 184793.2904445632425417223, 1088204.76946882876749847,
222
+ 3338152.967987029735917223, 5106661.678927352456275255,
223
+ 3074109.054850539556250927 ]
224
+
225
+ lg_p4 = [ 14745.02166059939948905062,
226
+ 2426813.369486704502836312, 121475557.4045093227939592,
227
+ 2663432449.630976949898078, 29403789566.34553899906876,
228
+ 170266573776.5398868392998, 492612579337.743088758812,
229
+ 560625185622.3951465078242 ]
230
+
231
+ lg_q1 = [ 67.48212550303777196073036,
232
+ 1113.332393857199323513008, 7738.757056935398733233834,
233
+ 27639.87074403340708898585, 54993.10206226157329794414,
234
+ 61611.22180066002127833352, 36351.27591501940507276287,
235
+ 8785.536302431013170870835 ]
236
+
237
+ lg_q2 = [ 183.0328399370592604055942,
238
+ 7765.049321445005871323047, 133190.3827966074194402448,
239
+ 1136705.821321969608938755, 5267964.117437946917577538,
240
+ 13467014.54311101692290052, 17827365.30353274213975932,
241
+ 9533095.591844353613395747 ]
242
+
243
+ lg_q4 = [ 2690.530175870899333379843,
244
+ 639388.5654300092398984238, 41355999.30241388052042842,
245
+ 1120872109.61614794137657, 14886137286.78813811542398,
246
+ 101680358627.2438228077304, 341747634550.7377132798597,
247
+ 446315818741.9713286462081 ]
248
+
249
+ lg_c = [ -0.001910444077728,8.4171387781295e-4,
250
+ -5.952379913043012e-4, 7.93650793500350248e-4,
251
+ -0.002777777777777681622553, 0.08333333333333333331554247,
252
+ 0.0057083835261 ]
253
+
254
+ # Rough estimate of the fourth root of logGamma_xBig
255
+ lg_frtbig = 2.25e76
256
+ pnt68 = 0.6796875
257
+
258
+ if x == logGammaCache_x
259
+ return logGammaCache_res
260
+ end
261
+
262
+ y = x
263
+ if y > 0.0 && y <= Log_gamma_x_max_value
264
+ if y <= Eps
265
+ res = -Math.log(y)
266
+ elsif y <= 1.5
267
+ # EPS .LT. X .LE. 1.5
268
+ if y < pnt68
269
+ corr = -Math.log(y)
270
+ # xm1 is x-m-one, not x-m-L
271
+ xm1 = y
272
+ else
273
+ corr = 0.0
274
+ xm1 = y - 1.0
275
+ end
276
+ if y <= 0.5 || y >= pnt68
277
+ xden = 1.0
278
+ xnum = 0.0
279
+ for i in (0...8)
280
+ xnum = xnum * xm1 + lg_p1[i]
281
+ xden = xden * xm1 + lg_q1[i]
282
+ end
283
+ res = corr * xm1 * (lg_d1 + xm1 * (xnum / xden))
284
+ else
285
+ xm2 = y - 1.0
286
+ xden = 1.0
287
+ xnum = 0.0
288
+ for i in (0 ... 8)
289
+ xnum = xnum * xm2 + lg_p2[i]
290
+ xden = xden * xm2 + lg_q2[i]
291
+ end
292
+ res = corr + xm2 * (lg_d2 + xm2 * (xnum / xden))
293
+ end
294
+ elsif y <= 4.0
295
+ # 1.5 .LT. X .LE. 4.0
296
+ xm2 = y - 2.0
297
+ xden = 1.0
298
+ xnum = 0.0
299
+ for i in (0 ... 8)
300
+ xnum = xnum * xm2 + lg_p2[i]
301
+ xden = xden * xm2 + lg_q2[i]
302
+ end
303
+ res = xm2 * (lg_d2 + xm2 * (xnum / xden))
304
+ elsif y <= 12.0
305
+ # 4.0 .LT. X .LE. 12.0
306
+ xm4 = y - 4.0
307
+ xden = -1.0
308
+ xnum = 0.0
309
+ for i in (0 ... 8)
310
+ xnum = xnum * xm4 + lg_p4[i]
311
+ xden = xden * xm4 + lg_q4[i]
312
+ end
313
+ res = lg_d4 + xm4 * (xnum / xden)
314
+ else
315
+ # Evaluate for argument .GE. 12.0
316
+ res = 0.0
317
+ if y <= lg_frtbig
318
+ res = lg_c[6]
319
+ ysq = y * y
320
+ for i in (0...6)
321
+ res = res / ysq + lg_c[i]
322
+ end
323
+ end
324
+ res = res/y
325
+ corr = Math.log(y)
326
+ res = res + Math.log(Sqrt2pi) - 0.5 * corr
327
+ res = res + y * (corr - 1.0)
328
+ end
329
+ else
330
+ #return for bad arguments
331
+ res = Max_value
332
+ end
333
+ # final adjustments and return
334
+ logGammaCache_x = x
335
+ logGammaCache_res = res
336
+ return res
337
+ end
338
+
339
+
340
+ # Incomplete gamma function.
341
+ # The computation is based on approximations presented in
342
+ # Numerical Recipes, Chapter 6.2 (W.H. Press et al, 1992).
343
+ # @param a require a>=0
344
+ # @param x require x>=0
345
+ # @return 0 if x<0, a<=0 or a>2.55E305 to avoid errors and over/underflow
346
+ # @author Jaco van Kooten
347
+
348
+ def incomplete_gamma(a, x)
349
+ if x <= 0.0 || a <= 0.0 || a > Log_gamma_x_max_value
350
+ return 0.0
351
+ elsif x < (a + 1.0)
352
+ return gamma_series_expansion(a, x)
353
+ else
354
+ return 1.0-gamma_fraction(a, x)
355
+ end
356
+ end
357
+
358
+ # Author:: Jaco van Kooten
359
+ def gamma_series_expansion(a, x)
360
+ ap = a
361
+ del = 1.0 / a
362
+ sum = del
363
+ for n in (1...Max_iterations)
364
+ ap += 1
365
+ del *= x / ap
366
+ sum += del
367
+ if del < sum * Precision
368
+ return sum * Math.exp(-x + a * Math.log(x) - log_gamma(a))
369
+ end
370
+ end
371
+ return "Maximum iterations exceeded: please file a bug report."
372
+ end
373
+
374
+ # Author:: Jaco van Kooten
375
+ def gamma_fraction(a, x)
376
+ b = x + 1.0 - a
377
+ c = 1.0 / Xminin
378
+ d = 1.0 / b
379
+ h = d
380
+ del= 0.0
381
+ an = 0.0
382
+ for i in (1...Max_iterations)
383
+ if (del-1.0).abs > Precision
384
+ an = -i * (i - a)
385
+ b += 2.0
386
+ d = an * d + b
387
+ c = b + an / c
388
+ if c.abs < Xminin
389
+ c = Xminin
390
+ if d.abs < Xminin
391
+ c = Xminin
392
+ d = 1.0 / d
393
+ del = d * c
394
+ h *= del
395
+ end
396
+ end
397
+ end
398
+ return Math.exp(-x + a * Math.log(x) - log_gamma(a)) * h
399
+ end
400
+ end
401
+
402
+ # Beta function.
403
+ #
404
+ # Author:: Jaco van Kooten
405
+
406
+ def beta(p, q)
407
+ if p <= 0.0 || q <= 0.0 || (p + q) > Log_gamma_x_max_value
408
+ return 0.0
409
+ else
410
+ return Math.exp(log_beta(p, q))
411
+ end
412
+ end
413
+
414
+ # Incomplete Beta function.
415
+ #
416
+ # Author:: Jaco van Kooten
417
+ # Author:: Paul Meagher
418
+ #
419
+ # The computation is based on formulas from Numerical Recipes,
420
+ # Chapter 6.4 (W.H. Press et al, 1992).
421
+
422
+ def incomplete_beta(x, p, q)
423
+ if x <= 0.0
424
+ return 0.0
425
+ elsif x >= 1.0
426
+ return 1.0
427
+ elsif p <= 0.0 || q <= 0.0 || (p + q) > Log_gamma_x_max_value
428
+ return 0.0
429
+ else
430
+ beta_gam = Math.exp( -log_beta(p, q) + p * Math.log(x) + q * Math.log(1.0 - x) )
431
+ if x < (p + 1.0) / (p + q + 2.0)
432
+ return beta_gam * beta_fraction(x, p, q) / p
433
+ else
434
+ beta_frac = beta_fraction(1.0 - x, p, q)
435
+ return 1.0 - (beta_gam * beta_fraction(1.0 - x, q, p) / q)
436
+ end
437
+ end
438
+ end
439
+
440
+
441
+ # Evaluates of continued fraction part of incomplete beta function.
442
+ # Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
443
+ # Author:: Jaco van Kooten
444
+
445
+ def beta_fraction(x, p, q)
446
+ c = 1.0
447
+ sum_pq = p + q
448
+ p_plus = p + 1.0
449
+ p_minus = p - 1.0
450
+ h = 1.0 - sum_pq * x / p_plus
451
+ if h.abs < Xminin
452
+ h = Xminin
453
+ end
454
+ h = 1.0 / h
455
+ frac = h
456
+ m = 1
457
+ delta = 0.0
458
+
459
+ while (m <= Max_iterations) && ((delta - 1.0).abs > Precision)
460
+ m2 = 2 * m
461
+ # even index for d
462
+ d = m * (q - m) * x / ( (p_minus + m2) * (p + m2))
463
+ h = 1.0 + d * h
464
+ if h.abs < Xminin
465
+ h = Xminin
466
+ end
467
+ h = 1.0 / h
468
+ c = 1.0 + d / c
469
+ if c.abs < Xminin
470
+ c = Xminin
471
+ end
472
+ frac *= h * c
473
+ # odd index for d
474
+ d = -(p + m) * (sum_pq + m) * x / ((p + m2) * (p_plus + m2))
475
+ h = 1.0 + d * h
476
+ if h.abs < Xminin
477
+ h = Xminin
478
+ end
479
+ h = 1.0 / h
480
+ c = 1.0 + d / c
481
+ if c.abs < Xminin
482
+ c = Xminin
483
+ end
484
+ delta = h * c
485
+ frac *= delta
486
+ m += 1
487
+ end
488
+ return frac
489
+ end
490
+
491
+
492
+
493
+ # Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
494
+ #
495
+ # Developed at SunSoft, a Sun Microsystems, Inc. business.
496
+ # Permission to use, copy, modify, and distribute this
497
+ # software is freely granted, provided that this notice
498
+ # is preserved.
499
+ #
500
+ # x
501
+ # 2 |\
502
+ # erf(x) = --------- | exp(-t*t)dt
503
+ # sqrt(pi) \|
504
+ # 0
505
+ #
506
+ # erfc(x) = 1-erf(x)
507
+ # Note that
508
+ # erf(-x) = -erf(x)
509
+ # erfc(-x) = 2 - erfc(x)
510
+ #
511
+ # Method:
512
+ # 1. For |x| in [0, 0.84375]
513
+ # erf(x) = x + x*R(x^2)
514
+ # erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
515
+ # = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
516
+ # where R = P/Q where P is an odd poly of degree 8 and
517
+ # Q is an odd poly of degree 10.
518
+ # -57.90
519
+ # | R - (erf(x)-x)/x | <= 2
520
+ #
521
+ #
522
+ # Remark. The formula is derived by noting
523
+ # erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
524
+ # and that
525
+ # 2/sqrt(pi) = 1.128379167095512573896158903121545171688
526
+ # is close to one. The interval is chosen because the fix
527
+ # point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
528
+ # near 0.6174), and by some experiment, 0.84375 is chosen to
529
+ # guarantee the error is less than one ulp for erf.
530
+ #
531
+ # 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
532
+ # c = 0.84506291151 rounded to single (24 bits)
533
+ # erf(x) = sign(x) * (c + P1(s)/Q1(s))
534
+ # erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
535
+ # 1+(c+P1(s)/Q1(s)) if x < 0
536
+ # |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
537
+ # Remark: here we use the taylor series expansion at x=1.
538
+ # erf(1+s) = erf(1) + s*Poly(s)
539
+ # = 0.845.. + P1(s)/Q1(s)
540
+ # That is, we use rational approximation to approximate
541
+ # erf(1+s) - (c = (single)0.84506291151)
542
+ # Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
543
+ # where
544
+ # P1(s) = degree 6 poly in s
545
+ # Q1(s) = degree 6 poly in s
546
+ #
547
+ # 3. For x in [1.25,1/0.35(~2.857143)],
548
+ # erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
549
+ # erf(x) = 1 - erfc(x)
550
+ # where
551
+ # R1(z) = degree 7 poly in z, (z=1/x^2)
552
+ # S1(z) = degree 8 poly in z
553
+ #
554
+ # 4. For x in [1/0.35,28]
555
+ # erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
556
+ # = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
557
+ # = 2.0 - tiny (if x <= -6)
558
+ # erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
559
+ # erf(x) = sign(x)*(1.0 - tiny)
560
+ # where
561
+ # R2(z) = degree 6 poly in z, (z=1/x^2)
562
+ # S2(z) = degree 7 poly in z
563
+ #
564
+ # Note1:
565
+ # To compute exp(-x*x-0.5625+R/S), let s be a single
566
+ # precision number and s := x then
567
+ # -x*x = -s*s + (s-x)*(s+x)
568
+ # exp(-x*x-0.5626+R/S) =
569
+ # exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S)
570
+ # Note2:
571
+ # Here 4 and 5 make use of the asymptotic series
572
+ # exp(-x*x)
573
+ # erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
574
+ # x*sqrt(pi)
575
+ # We use rational approximation to approximate
576
+ # g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
577
+ # Here is the error bound for R1/S1 and R2/S2
578
+ # |R1/S1 - f(x)| < 2**(-62.57)
579
+ # |R2/S2 - f(x)| < 2**(-61.52)
580
+ #
581
+ # 5. For inf > x >= 28
582
+ # erf(x) = sign(x) *(1 - tiny) (raise inexact)
583
+ # erfc(x) = tiny*tiny (raise underflow) if x > 0
584
+ # = 2 - tiny if x<0
585
+ #
586
+ # 7. Special case:
587
+ # erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
588
+ # erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
589
+ # erfc/erf(NaN) is NaN
590
+ #
591
+ # $efx8 = 1.02703333676410069053e00
592
+ #
593
+ # Coefficients for approximation to erf on [0,0.84375]
594
+ #
595
+
596
+ # Error function.
597
+ # Based on C-code for the error function developed at Sun Microsystems.
598
+ # Author:: Jaco van Kooten
599
+
600
+ def error(x)
601
+ e_efx = 1.28379167095512586316e-01
602
+
603
+ ePp = [ 1.28379167095512558561e-01,
604
+ -3.25042107247001499370e-01,
605
+ -2.84817495755985104766e-02,
606
+ -5.77027029648944159157e-03,
607
+ -2.37630166566501626084e-05 ]
608
+
609
+ eQq = [ 3.97917223959155352819e-01,
610
+ 6.50222499887672944485e-02,
611
+ 5.08130628187576562776e-03,
612
+ 1.32494738004321644526e-04,
613
+ -3.96022827877536812320e-06 ]
614
+
615
+ # Coefficients for approximation to erf in [0.84375,1.25]
616
+ ePa = [-2.36211856075265944077e-03,
617
+ 4.14856118683748331666e-01,
618
+ -3.72207876035701323847e-01,
619
+ 3.18346619901161753674e-01,
620
+ -1.10894694282396677476e-01,
621
+ 3.54783043256182359371e-02,
622
+ -2.16637559486879084300e-03 ]
623
+
624
+ eQa = [ 1.06420880400844228286e-01,
625
+ 5.40397917702171048937e-01,
626
+ 7.18286544141962662868e-02,
627
+ 1.26171219808761642112e-01,
628
+ 1.36370839120290507362e-02,
629
+ 1.19844998467991074170e-02 ]
630
+
631
+ e_erx = 8.45062911510467529297e-01
632
+
633
+ abs_x = (if x >= 0.0 then x else -x end)
634
+ # 0 < |x| < 0.84375
635
+ if abs_x < 0.84375
636
+ #|x| < 2**-28
637
+ if abs_x < 3.7252902984619141e-9
638
+ retval = abs_x + abs_x * e_efx
639
+ else
640
+ s = x * x
641
+ p = ePp[0] + s * (ePp[1] + s * (ePp[2] + s * (ePp[3] + s * ePp[4])))
642
+
643
+ q = 1.0 + s * (eQq[0] + s * (eQq[1] + s *
644
+ ( eQq[2] + s * (eQq[3] + s * eQq[4]))))
645
+ retval = abs_x + abs_x * (p / q)
646
+ end
647
+ elsif abs_x < 1.25
648
+ s = abs_x - 1.0
649
+ p = ePa[0] + s * (ePa[1] + s *
650
+ (ePa[2] + s * (ePa[3] + s *
651
+ (ePa[4] + s * (ePa[5] + s * ePa[6])))))
652
+
653
+ q = 1.0 + s * (eQa[0] + s *
654
+ (eQa[1] + s * (eQa[2] + s *
655
+ (eQa[3] + s * (eQa[4] + s * eQa[5])))))
656
+ retval = e_erx + p / q
657
+
658
+ elsif abs_x >= 6.0
659
+ retval = 1.0
660
+ else
661
+ retval = 1.0 - complementary_error(abs_x)
662
+ end
663
+ return (if x >= 0.0 then retval else -retval end)
664
+ end
665
+
666
+ # Complementary error function.
667
+ # Based on C-code for the error function developed at Sun Microsystems.
668
+ # author Jaco van Kooten
669
+
670
+ def complementary_error(x)
671
+ # Coefficients for approximation of erfc in [1.25,1/.35]
672
+
673
+ eRa = [-9.86494403484714822705e-03,
674
+ -6.93858572707181764372e-01,
675
+ -1.05586262253232909814e01,
676
+ -6.23753324503260060396e01,
677
+ -1.62396669462573470355e02,
678
+ -1.84605092906711035994e02,
679
+ -8.12874355063065934246e01,
680
+ -9.81432934416914548592e00 ]
681
+
682
+ eSa = [ 1.96512716674392571292e01,
683
+ 1.37657754143519042600e02,
684
+ 4.34565877475229228821e02,
685
+ 6.45387271733267880336e02,
686
+ 4.29008140027567833386e02,
687
+ 1.08635005541779435134e02,
688
+ 6.57024977031928170135e00,
689
+ -6.04244152148580987438e-02 ]
690
+
691
+ # Coefficients for approximation to erfc in [1/.35,28]
692
+
693
+ eRb = [-9.86494292470009928597e-03,
694
+ -7.99283237680523006574e-01,
695
+ -1.77579549177547519889e01,
696
+ -1.60636384855821916062e02,
697
+ -6.37566443368389627722e02,
698
+ -1.02509513161107724954e03,
699
+ -4.83519191608651397019e02 ]
700
+
701
+ eSb = [ 3.03380607434824582924e01,
702
+ 3.25792512996573918826e02,
703
+ 1.53672958608443695994e03,
704
+ 3.19985821950859553908e03,
705
+ 2.55305040643316442583e03,
706
+ 4.74528541206955367215e02,
707
+ -2.24409524465858183362e01 ]
708
+
709
+ abs_x = (if x >= 0.0 then x else -x end)
710
+ if abs_x < 1.25
711
+ retval = 1.0 - error(abs_x)
712
+ elsif abs_x > 28.0
713
+ retval = 0.0
714
+
715
+ # 1.25 < |x| < 28
716
+ else
717
+ s = 1.0/(abs_x * abs_x)
718
+ if abs_x < 2.8571428
719
+ r = eRa[0] + s * (eRa[1] + s *
720
+ (eRa[2] + s * (eRa[3] + s * (eRa[4] + s *
721
+ (eRa[5] + s *(eRa[6] + s * eRa[7])
722
+ )))))
723
+
724
+ s = 1.0 + s * (eSa[0] + s * (eSa[1] + s *
725
+ (eSa[2] + s * (eSa[3] + s * (eSa[4] + s *
726
+ (eSa[5] + s * (eSa[6] + s * eSa[7])))))))
727
+
728
+ else
729
+ r = eRb[0] + s * (eRb[1] + s *
730
+ (eRb[2] + s * (eRb[3] + s * (eRb[4] + s *
731
+ (eRb[5] + s * eRb[6])))))
732
+
733
+ s = 1.0 + s * (eSb[0] + s *
734
+ (eSb[1] + s * (eSb[2] + s * (eSb[3] + s *
735
+ (eSb[4] + s * (eSb[5] + s * eSb[6]))))))
736
+ end
737
+ retval = Math.exp(-x * x - 0.5625 + r/s) / abs_x
738
+ end
739
+ return ( if x >= 0.0 then retval else 2.0 - retval end )
740
+ end
741
+ end
742
+ end