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.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +4 -6
  3. data/.yardopts +5 -0
  4. data/History.txt +3 -0
  5. data/README.md +87 -44
  6. data/benchmark/binomial_coefficient.rb +19 -23
  7. data/benchmark/binomial_coefficient/experiment.rb +33 -36
  8. data/benchmark/factorial_hash.rb +7 -8
  9. data/benchmark/factorial_method.rb +4 -6
  10. data/benchmark/odd.rb +6 -7
  11. data/benchmark/power.rb +11 -11
  12. data/bin/distribution +26 -26
  13. data/distribution.gemspec +3 -4
  14. data/lib/distribution.rb +55 -96
  15. data/lib/distribution/beta/gsl.rb +10 -5
  16. data/lib/distribution/beta/ruby.rb +3 -1
  17. data/lib/distribution/binomial/ruby.rb +5 -2
  18. data/lib/distribution/bivariatenormal.rb +4 -5
  19. data/lib/distribution/bivariatenormal/gsl.rb +2 -2
  20. data/lib/distribution/bivariatenormal/java.rb +1 -1
  21. data/lib/distribution/bivariatenormal/ruby.rb +245 -254
  22. data/lib/distribution/chisquare.rb +8 -10
  23. data/lib/distribution/chisquare/gsl.rb +24 -19
  24. data/lib/distribution/chisquare/java.rb +1 -1
  25. data/lib/distribution/chisquare/ruby.rb +25 -25
  26. data/lib/distribution/chisquare/statistics2.rb +16 -13
  27. data/lib/distribution/distributable.rb +40 -0
  28. data/lib/distribution/exponential.rb +4 -5
  29. data/lib/distribution/exponential/gsl.rb +13 -9
  30. data/lib/distribution/exponential/ruby.rb +14 -9
  31. data/lib/distribution/f.rb +1 -1
  32. data/lib/distribution/f/gsl.rb +26 -22
  33. data/lib/distribution/f/java.rb +1 -1
  34. data/lib/distribution/f/ruby.rb +16 -19
  35. data/lib/distribution/f/statistics2.rb +22 -19
  36. data/lib/distribution/gamma.rb +5 -7
  37. data/lib/distribution/gamma/gsl.rb +13 -9
  38. data/lib/distribution/gamma/java.rb +1 -1
  39. data/lib/distribution/gamma/ruby.rb +5 -11
  40. data/lib/distribution/hypergeometric.rb +5 -8
  41. data/lib/distribution/hypergeometric/gsl.rb +4 -5
  42. data/lib/distribution/hypergeometric/java.rb +1 -1
  43. data/lib/distribution/hypergeometric/ruby.rb +34 -35
  44. data/lib/distribution/logistic.rb +5 -8
  45. data/lib/distribution/logistic/ruby.rb +13 -8
  46. data/lib/distribution/lognormal.rb +5 -7
  47. data/lib/distribution/lognormal/gsl.rb +8 -6
  48. data/lib/distribution/lognormal/ruby.rb +5 -9
  49. data/lib/distribution/math_extension.rb +6 -15
  50. data/lib/distribution/math_extension/chebyshev_series.rb +281 -272
  51. data/lib/distribution/math_extension/erfc.rb +26 -29
  52. data/lib/distribution/math_extension/exponential_integral.rb +17 -17
  53. data/lib/distribution/math_extension/gammastar.rb +19 -20
  54. data/lib/distribution/math_extension/gsl_utilities.rb +12 -12
  55. data/lib/distribution/math_extension/incomplete_beta.rb +52 -61
  56. data/lib/distribution/math_extension/incomplete_gamma.rb +166 -168
  57. data/lib/distribution/math_extension/log_utilities.rb +20 -22
  58. data/lib/distribution/normal.rb +11 -13
  59. data/lib/distribution/normal/gsl.rb +13 -10
  60. data/lib/distribution/normal/java.rb +14 -13
  61. data/lib/distribution/normal/ruby.rb +68 -58
  62. data/lib/distribution/normal/statistics2.rb +5 -2
  63. data/lib/distribution/normalmultivariate.rb +64 -64
  64. data/lib/distribution/poisson.rb +11 -13
  65. data/lib/distribution/poisson/gsl.rb +7 -7
  66. data/lib/distribution/poisson/java.rb +19 -24
  67. data/lib/distribution/poisson/ruby.rb +38 -9
  68. data/lib/distribution/shorthand.rb +17 -0
  69. data/lib/distribution/t.rb +13 -15
  70. data/lib/distribution/t/gsl.rb +27 -24
  71. data/lib/distribution/t/java.rb +1 -1
  72. data/lib/distribution/t/ruby.rb +99 -100
  73. data/lib/distribution/t/statistics2.rb +19 -19
  74. data/lib/distribution/uniform.rb +26 -0
  75. data/lib/distribution/uniform/gsl.rb +36 -0
  76. data/lib/distribution/uniform/ruby.rb +91 -0
  77. data/lib/distribution/version.rb +1 -1
  78. data/lib/distribution/weibull.rb +6 -7
  79. data/lib/distribution/weibull/gsl.rb +16 -16
  80. data/lib/distribution/weibull/ruby.rb +30 -23
  81. data/spec/beta_spec.rb +45 -47
  82. data/spec/binomial_spec.rb +77 -85
  83. data/spec/bivariatenormal_spec.rb +28 -35
  84. data/spec/chisquare_spec.rb +48 -52
  85. data/spec/distribution_spec.rb +10 -10
  86. data/spec/exponential_spec.rb +44 -49
  87. data/spec/f_spec.rb +4 -4
  88. data/spec/gamma_spec.rb +50 -53
  89. data/spec/hypergeometric_spec.rb +63 -69
  90. data/spec/logistic_spec.rb +32 -37
  91. data/spec/lognormal_spec.rb +25 -31
  92. data/spec/math_extension_spec.rb +192 -210
  93. data/spec/normal_spec.rb +80 -73
  94. data/spec/poisson_spec.rb +63 -41
  95. data/spec/shorthand_spec.rb +19 -22
  96. data/spec/spec_helper.rb +8 -9
  97. data/spec/t_spec.rb +63 -77
  98. data/spec/uniform_spec.rb +154 -0
  99. data/spec/weibull_spec.rb +13 -14
  100. metadata +17 -8
@@ -1,281 +1,272 @@
1
1
  module Distribution
2
- #
2
+ #
3
3
  # Ruby version implements three methods on this module:
4
4
  # * Genz:: Used by default, with improvement to calculate p on rho > 0.95
5
5
  # * Hull:: Port from a C++ code
6
6
  # * Jantaravareerat:: Iterative (slow and buggy)
7
- #
8
-
7
+ #
8
+
9
9
  module BivariateNormal
10
10
  module Ruby_
11
- class << self
12
- SIDE=0.1 # :nodoc:
13
- LIMIT=5 # :nodoc:
14
- # Return the partial derivative of cdf over x, with y and rho constant
15
- # Reference:
16
- # * Tallis, 1962, p.346, cited by Olsson, 1979
17
- def partial_derivative_cdf_x(x,y,rho)
18
- Distribution::Normal.pdf(x) * Distribution::Normal.cdf((y-rho*x).quo( Math::sqrt( 1 - rho**2 )))
19
- end
20
- alias :pd_cdf_x :partial_derivative_cdf_x
21
- # Probability density function for a given x, y and rho value.
22
- #
23
- # Source: http://en.wikipedia.org/wiki/Multivariate_normal_distribution
24
- def pdf(x,y, rho, s1=1.0, s2=1.0)
25
- 1.quo(2 * Math::PI * s1 * s2 * Math::sqrt( 1 - rho**2 )) * (Math::exp(-(1.quo(2*(1-rho**2))) *
26
- ((x**2.quo(s1)) + (y**2.quo(s2)) - (2*rho*x*y).quo(s1*s2))))
27
- end
28
-
29
- def f(x,y,aprime,bprime,rho)
30
- r=aprime*(2*x-aprime)+bprime*(2*y-bprime)+2*rho*(x-aprime)*(y-bprime)
31
- Math::exp(r)
32
- end
33
-
34
- # CDF for a given x, y and rho value.
35
- # Uses Genz algorithm (cdf_genz method).
36
- #
37
- def cdf(a,b,rho)
38
- cdf_genz(a,b,rho)
39
- end
40
-
41
- def sgn(x)
42
- if(x>=0)
43
- 1
44
- else
45
- -1
46
- end
47
- end
48
-
49
- # Normal cumulative distribution function (cdf) for a given x, y and rho.
50
- # Based on Hull (1993, cited by Arne, 2003)
51
- #
52
- # References:
53
- # * Arne, B.(2003). Financial Numerical Recipes in C ++. Available on http://finance.bi.no/~bernt/gcc_prog/recipes/recipes/node23.html
54
- def cdf_hull(a,b,rho)
55
- #puts "a:#{a} - b:#{b} - rho:#{rho}"
56
- if (a<=0 and b<=0 and rho<=0)
57
- # puts "ruta 1"
58
- aprime=a.quo(Math::sqrt(2.0*(1.0-rho**2)))
59
- bprime=b.quo(Math::sqrt(2.0*(1.0-rho**2)))
60
- aa=[0.3253030, 0.4211071, 0.1334425, 0.006374323]
61
- bb=[0.1337764, 0.6243247, 1.3425378, 2.2626645]
62
- sum=0
63
- 4.times do |i|
64
- 4.times do |j|
65
- sum+=aa[i]*aa[j] * f(bb[i], bb[j], aprime, bprime,rho)
66
- end
67
- end
68
- sum=sum*(Math::sqrt(1.0-rho**2).quo(Math::PI))
69
- return sum
70
- elsif(a*b*rho<=0.0)
71
-
72
- #puts "ruta 2"
73
- if(a<=0 and b>=0 and rho>=0)
74
- return Distribution::Normal.cdf(a) - cdf(a,-b,-rho)
75
- elsif (a>=0.0 and b<=0.0 and rho>=0)
76
- return Distribution::Normal.cdf(b) - cdf(-a,b,-rho)
77
- elsif (a>=0.0 and b>=0.0 and rho<=0)
78
- return Distribution::Normal.cdf(a) + Distribution::Normal.cdf(b) - 1.0 + cdf(-a,-b,rho)
11
+ class << self
12
+ SIDE = 0.1 # :nodoc:
13
+ LIMIT = 5 # :nodoc:
14
+ # Return the partial derivative of cdf over x, with y and rho constant
15
+ # Reference:
16
+ # * Tallis, 1962, p.346, cited by Olsson, 1979
17
+ def partial_derivative_cdf_x(x, y, rho)
18
+ Distribution::Normal.pdf(x) * Distribution::Normal.cdf((y - rho * x).quo(Math.sqrt(1 - rho**2)))
19
+ end
20
+ alias_method :pd_cdf_x, :partial_derivative_cdf_x
21
+ # Probability density function for a given x, y and rho value.
22
+ #
23
+ # Source: http://en.wikipedia.org/wiki/Multivariate_normal_distribution
24
+ def pdf(x, y, rho, s1 = 1.0, s2 = 1.0)
25
+ 1.quo(2 * Math::PI * s1 * s2 * Math.sqrt(1 - rho**2)) * (Math.exp(-(1.quo(2 * (1 - rho**2))) *
26
+ ((x**2.quo(s1)) + (y**2.quo(s2)) - (2 * rho * x * y).quo(s1 * s2))))
27
+ end
28
+
29
+ def f(x, y, aprime, bprime, rho)
30
+ r = aprime * (2 * x - aprime) + bprime * (2 * y - bprime) + 2 * rho * (x - aprime) * (y - bprime)
31
+ Math.exp(r)
32
+ end
33
+
34
+ # CDF for a given x, y and rho value.
35
+ # Uses Genz algorithm (cdf_genz method).
36
+ #
37
+ def cdf(a, b, rho)
38
+ cdf_genz(a, b, rho)
39
+ end
40
+
41
+ def sgn(x)
42
+ if (x >= 0)
43
+ 1
44
+ else
45
+ -1
79
46
  end
80
- elsif (a*b*rho>=0.0)
81
- #puts "ruta 3"
82
- denum=Math::sqrt(a**2 - 2*rho*a*b + b**2)
83
- rho1=((rho*a-b)*sgn(a)).quo(denum)
84
- rho2=((rho*b-a)*sgn(b)).quo(denum)
85
- delta=(1.0-sgn(a)*sgn(b)).quo(4)
86
- #puts "#{rho1} - #{rho2}"
87
- return cdf(a, 0.0, rho1) + cdf(b, 0.0, rho2) - delta
88
47
  end
89
- raise "Should'nt be here! #{a} - #{b} #{rho}"
90
- end
91
-
92
- # CDF. Iterative method by Jantaravareerat (n/d)
93
- #
94
- # Reference:
95
- # * Jantaravareerat, M. & Thomopoulos, N. (n/d). Tables for standard bivariate normal distribution
96
-
97
- def cdf_jantaravareerat(x,y,rho,s1=1,s2=1)
98
- # Special cases
99
- return 1 if x>LIMIT and y>LIMIT
100
- return 0 if x<-LIMIT or y<-LIMIT
101
- return Distribution::Normal.cdf(y) if x>LIMIT
102
- return Distribution::Normal.cdf(x) if y>LIMIT
103
-
104
- #puts "x:#{x} - y:#{y}"
105
- x=-LIMIT if x<-LIMIT
106
- x=LIMIT if x>LIMIT
107
- y=-LIMIT if y<-LIMIT
108
- y=LIMIT if y>LIMIT
109
48
 
110
- x_squares=((LIMIT+x) / SIDE).to_i
111
- y_squares=((LIMIT+y) / SIDE).to_i
112
- sum=0
113
- x_squares.times do |i|
114
- y_squares.times do |j|
115
- z1=-LIMIT+(i+1)*SIDE
116
- z2=-LIMIT+(j+1)*SIDE
117
- #puts " #{z1}-#{z2}"
118
- h=(pdf(z1,z2,rho,s1,s2)+pdf(z1-SIDE,z2,rho,s1,s2)+pdf(z1,z2-SIDE,rho,s1,s2) + pdf(z1-SIDE,z2-SIDE,rho,s1,s2)).quo(4)
119
- sum+= (SIDE**2)*h # area
49
+ # Normal cumulative distribution function (cdf) for a given x, y and rho.
50
+ # Based on Hull (1993, cited by Arne, 2003)
51
+ #
52
+ # References:
53
+ # * Arne, B.(2003). Financial Numerical Recipes in C ++. Available on http://finance.bi.no/~bernt/gcc_prog/recipes/recipes/node23.html
54
+ def cdf_hull(a, b, rho)
55
+ # puts "a:#{a} - b:#{b} - rho:#{rho}"
56
+ if a <= 0 && b <= 0 && rho <= 0
57
+ # puts "ruta 1"
58
+ aprime = a.quo(Math.sqrt(2.0 * (1.0 - rho**2)))
59
+ bprime = b.quo(Math.sqrt(2.0 * (1.0 - rho**2)))
60
+ aa = [0.3253030, 0.4211071, 0.1334425, 0.006374323]
61
+ bb = [0.1337764, 0.6243247, 1.3425378, 2.2626645]
62
+ sum = 0
63
+ 4.times do |i|
64
+ 4.times do |j|
65
+ sum += aa[i] * aa[j] * f(bb[i], bb[j], aprime, bprime, rho)
66
+ end
67
+ end
68
+ sum *= (Math.sqrt(1.0 - rho**2).quo(Math::PI))
69
+ return sum
70
+ elsif (a * b * rho <= 0.0)
71
+
72
+ # puts "ruta 2"
73
+ if a <= 0 && b >= 0 && rho >= 0
74
+ return Distribution::Normal.cdf(a) - cdf(a, -b, -rho)
75
+ elsif a >= 0.0 && b <= 0.0 && rho >= 0
76
+ return Distribution::Normal.cdf(b) - cdf(-a, b, -rho)
77
+ elsif a >= 0.0 && b >= 0.0 && rho <= 0
78
+ return Distribution::Normal.cdf(a) + Distribution::Normal.cdf(b) - 1.0 + cdf(-a, -b, rho)
79
+ end
80
+ elsif (a * b * rho >= 0.0)
81
+ # puts "ruta 3"
82
+ denum = Math.sqrt(a**2 - 2 * rho * a * b + b**2)
83
+ rho1 = ((rho * a - b) * sgn(a)).quo(denum)
84
+ rho2 = ((rho * b - a) * sgn(b)).quo(denum)
85
+ delta = (1.0 - sgn(a) * sgn(b)).quo(4)
86
+ # puts "#{rho1} - #{rho2}"
87
+ return cdf(a, 0.0, rho1) + cdf(b, 0.0, rho2) - delta
120
88
  end
89
+ fail "Should'nt be here! #{a} - #{b} #{rho}"
121
90
  end
122
- sum
123
- end
124
- # Normal cumulative distribution function (cdf) for a given x, y and rho.
125
- # Ported from Fortran code by Alan Genz
126
- #
127
- # Original documentation
128
- # DOUBLE PRECISION FUNCTION BVND( DH, DK, R )
129
- # A function for computing bivariate normal probabilities.
130
- #
131
- # Alan Genz
132
- # Department of Mathematics
133
- # Washington State University
134
- # Pullman, WA 99164-3113
135
- # Email : alangenz_AT_wsu.edu
136
- #
137
- # This function is based on the method described by
138
- # Drezner, Z and G.O. Wesolowsky, (1989),
139
- # On the computation of the bivariate normal integral,
140
- # Journal of Statist. Comput. Simul. 35, pp. 101-107,
141
- # with major modifications for double precision, and for |R| close to 1.
142
- #
143
- # Original location:
144
- # * http://www.math.wsu.edu/faculty/genz/software/fort77/tvpack.f
145
- def cdf_genz(x,y,rho)
146
- dh=-x
147
- dk=-y
148
- r=rho
149
- twopi = 6.283185307179586
150
-
151
- w=11.times.collect {[nil]*4};
152
- x=11.times.collect {[nil]*4}
153
-
154
- data=[
155
- 0.1713244923791705E+00, -0.9324695142031522E+00,
156
- 0.3607615730481384E+00, -0.6612093864662647E+00,
157
- 0.4679139345726904E+00, -0.2386191860831970E+00]
158
-
159
- (1..3).each {|i|
160
- w[i][1]=data[(i-1)*2]
161
- x[i][1]=data[(i-1)*2+1]
162
-
163
- }
164
- data=[
165
- 0.4717533638651177E-01,-0.9815606342467191E+00,
166
- 0.1069393259953183E+00,-0.9041172563704750E+00,
167
- 0.1600783285433464E+00,-0.7699026741943050E+00,
168
- 0.2031674267230659E+00,-0.5873179542866171E+00,
169
- 0.2334925365383547E+00,-0.3678314989981802E+00,
170
- 0.2491470458134029E+00,-0.1252334085114692E+00]
171
- (1..6).each {|i|
172
- w[i][2]=data[(i-1)*2]
173
- x[i][2]=data[(i-1)*2+1]
174
91
 
175
-
176
- }
177
- data=[
178
- 0.1761400713915212E-01,-0.9931285991850949E+00,
179
- 0.4060142980038694E-01,-0.9639719272779138E+00,
180
- 0.6267204833410906E-01,-0.9122344282513259E+00,
181
- 0.8327674157670475E-01,-0.8391169718222188E+00,
182
- 0.1019301198172404E+00,-0.7463319064601508E+00,
183
- 0.1181945319615184E+00,-0.6360536807265150E+00,
184
- 0.1316886384491766E+00,-0.5108670019508271E+00,
185
- 0.1420961093183821E+00,-0.3737060887154196E+00,
186
- 0.1491729864726037E+00,-0.2277858511416451E+00,
187
- 0.1527533871307259E+00,-0.7652652113349733E-01]
188
-
189
- (1..10).each {|i|
190
- w[i][3]=data[(i-1)*2]
191
- x[i][3]=data[(i-1)*2+1]
92
+ # CDF. Iterative method by Jantaravareerat (n/d)
93
+ #
94
+ # Reference:
95
+ # * Jantaravareerat, M. & Thomopoulos, N. (n/d). Tables for standard bivariate normal distribution
192
96
 
193
-
194
- }
195
-
196
-
197
- if ( r.abs < 0.3 )
198
- ng = 1
199
- lg = 3
200
- elsif ( r.abs < 0.75 )
201
- ng = 2
202
- lg = 6
203
- else
204
- ng = 3
205
- lg = 10
97
+ def cdf_jantaravareerat(x, y, rho, s1 = 1, s2 = 1)
98
+ # Special cases
99
+ return 1 if x > LIMIT && y > LIMIT
100
+ return 0 if x < -LIMIT || y < -LIMIT
101
+ return Distribution::Normal.cdf(y) if x > LIMIT
102
+ return Distribution::Normal.cdf(x) if y > LIMIT
103
+
104
+ # puts "x:#{x} - y:#{y}"
105
+ x = -LIMIT if x < -LIMIT
106
+ x = LIMIT if x > LIMIT
107
+ y = -LIMIT if y < -LIMIT
108
+ y = LIMIT if y > LIMIT
109
+
110
+ x_squares = ((LIMIT + x) / SIDE).to_i
111
+ y_squares = ((LIMIT + y) / SIDE).to_i
112
+ sum = 0
113
+ x_squares.times do |i|
114
+ y_squares.times do |j|
115
+ z1 = -LIMIT + (i + 1) * SIDE
116
+ z2 = -LIMIT + (j + 1) * SIDE
117
+ # puts " #{z1}-#{z2}"
118
+ h = (pdf(z1, z2, rho, s1, s2) + pdf(z1 - SIDE, z2, rho, s1, s2) + pdf(z1, z2 - SIDE, rho, s1, s2) + pdf(z1 - SIDE, z2 - SIDE, rho, s1, s2)).quo(4)
119
+ sum += (SIDE**2) * h # area
120
+ end
121
+ end
122
+ sum
206
123
  end
207
-
208
-
209
- h = dh
210
- k = dk
211
- hk = h*k
212
- bvn = 0
213
- if ( r.abs < 0.925 )
214
- if ( r.abs > 0 )
215
- hs = ( h*h + k*k ).quo(2)
216
- asr = Math::asin(r)
217
- (1..lg).each do |i|
218
- [-1,1].each do |is|
219
- sn = Math::sin(asr*(is* x[i][ng]+1).quo(2) )
220
- bvn = bvn + w[i][ng] * Math::exp( ( sn*hk-hs ).quo( 1-sn*sn ) )
221
- end # do
222
- end # do
223
- bvn = bvn*asr.quo( 2*twopi )
224
- end # if
225
- bvn = bvn + Distribution::Normal.cdf(-h) * Distribution::Normal.cdf(-k)
226
-
227
-
228
- else # r.abs
229
- if ( r < 0 )
230
- k = -k
231
- hk = -hk
124
+ # Normal cumulative distribution function (cdf) for a given x, y and rho.
125
+ # Ported from Fortran code by Alan Genz
126
+ #
127
+ # Original documentation
128
+ # DOUBLE PRECISION FUNCTION BVND( DH, DK, R )
129
+ # A function for computing bivariate normal probabilities.
130
+ #
131
+ # Alan Genz
132
+ # Department of Mathematics
133
+ # Washington State University
134
+ # Pullman, WA 99164-3113
135
+ # Email : alangenz_AT_wsu.edu
136
+ #
137
+ # This function is based on the method described by
138
+ # Drezner, Z and G.O. Wesolowsky, (1989),
139
+ # On the computation of the bivariate normal integral,
140
+ # Journal of Statist. Comput. Simul. 35, pp. 101-107,
141
+ # with major modifications for double precision, and for |R| close to 1.
142
+ #
143
+ # Original location:
144
+ # * http://www.math.wsu.edu/faculty/genz/software/fort77/tvpack.f
145
+ def cdf_genz(x, y, rho)
146
+ dh = -x
147
+ dk = -y
148
+ r = rho
149
+ twopi = 6.283185307179586
150
+
151
+ w = 11.times.collect { [nil] * 4 }
152
+ x = 11.times.collect { [nil] * 4 }
153
+
154
+ data = [
155
+ 0.1713244923791705E+00, -0.9324695142031522E+00,
156
+ 0.3607615730481384E+00, -0.6612093864662647E+00,
157
+ 0.4679139345726904E+00, -0.2386191860831970E+00]
158
+
159
+ (1..3).each do|i|
160
+ w[i][1] = data[(i - 1) * 2]
161
+ x[i][1] = data[(i - 1) * 2 + 1]
232
162
  end
233
-
234
- if ( r.abs < 1 )
235
- as = ( 1 - r )*( 1 + r )
236
- a = Math::sqrt(as)
237
- bs = ( h - k )**2
238
- c = ( 4 - hk ).quo(8)
239
- d = ( 12 - hk ).quo(16)
240
- asr = -( bs.quo(as) + hk ).quo(2)
241
- if ( asr > -100 )
242
- bvn = a*Math::exp(asr) * ( 1 - c*( bs - as )*( 1 - d*bs.quo(5) ).quo(3) + c*d*as*as.quo(5) )
243
- end
244
- if ( -hk < 100 )
245
- b = Math::sqrt(bs)
246
- bvn = bvn - Math::exp( -hk.quo(2) ) * Math::sqrt(twopi)*Distribution::Normal.cdf(-b.quo(a))*b *
247
- ( 1 - c*bs*( 1 - d*bs.quo(5) ).quo(3) )
163
+ data = [
164
+ 0.4717533638651177E-01, -0.9815606342467191E+00,
165
+ 0.1069393259953183E+00, -0.9041172563704750E+00,
166
+ 0.1600783285433464E+00, -0.7699026741943050E+00,
167
+ 0.2031674267230659E+00, -0.5873179542866171E+00,
168
+ 0.2334925365383547E+00, -0.3678314989981802E+00,
169
+ 0.2491470458134029E+00, -0.1252334085114692E+00]
170
+ (1..6).each do|i|
171
+ w[i][2] = data[(i - 1) * 2]
172
+ x[i][2] = data[(i - 1) * 2 + 1]
173
+ end
174
+ data = [
175
+ 0.1761400713915212E-01, -0.9931285991850949E+00,
176
+ 0.4060142980038694E-01, -0.9639719272779138E+00,
177
+ 0.6267204833410906E-01, -0.9122344282513259E+00,
178
+ 0.8327674157670475E-01, -0.8391169718222188E+00,
179
+ 0.1019301198172404E+00, -0.7463319064601508E+00,
180
+ 0.1181945319615184E+00, -0.6360536807265150E+00,
181
+ 0.1316886384491766E+00, -0.5108670019508271E+00,
182
+ 0.1420961093183821E+00, -0.3737060887154196E+00,
183
+ 0.1491729864726037E+00, -0.2277858511416451E+00,
184
+ 0.1527533871307259E+00, -0.7652652113349733E-01]
185
+
186
+ (1..10).each do|i|
187
+ w[i][3] = data[(i - 1) * 2]
188
+ x[i][3] = data[(i - 1) * 2 + 1]
189
+ end
190
+
191
+ if r.abs < 0.3
192
+ ng = 1
193
+ lg = 3
194
+ elsif r.abs < 0.75
195
+ ng = 2
196
+ lg = 6
197
+ else
198
+ ng = 3
199
+ lg = 10
200
+ end
201
+
202
+ h = dh
203
+ k = dk
204
+ hk = h * k
205
+ bvn = 0
206
+ if r.abs < 0.925
207
+ if r.abs > 0
208
+ hs = (h * h + k * k).quo(2)
209
+ asr = Math.asin(r)
210
+ (1..lg).each do |i|
211
+ [-1, 1].each do |is|
212
+ sn = Math.sin(asr * (is * x[i][ng] + 1).quo(2))
213
+ bvn += w[i][ng] * Math.exp((sn * hk - hs).quo(1 - sn * sn))
214
+ end # do
215
+ end # do
216
+ bvn *= asr.quo(2 * twopi)
217
+ end # if
218
+ bvn += Distribution::Normal.cdf(-h) * Distribution::Normal.cdf(-k)
219
+
220
+ else # r.abs
221
+ if r < 0
222
+ k = -k
223
+ hk = -hk
248
224
  end
249
-
250
-
251
- a = a.quo(2)
252
- (1..lg).each do |i|
253
- [-1,1].each do |is|
254
- xs = (a*( is*x[i][ng] + 1 ) )**2
255
- rs = Math::sqrt( 1 - xs )
256
- asr = -( bs/xs + hk ).quo(2)
257
- if ( asr > -100 )
258
- bvn = bvn + a*w[i][ng] * Math::exp( asr ) *
259
- ( Math::exp( -hk*( 1 - rs ).quo(2*( 1 + rs ) ) ) .quo(rs) - ( 1 + c*xs*( 1 + d*xs ) ) )
225
+
226
+ if r.abs < 1
227
+ as = (1 - r) * (1 + r)
228
+ a = Math.sqrt(as)
229
+ bs = (h - k)**2
230
+ c = (4 - hk).quo(8)
231
+ d = (12 - hk).quo(16)
232
+ asr = -(bs.quo(as) + hk).quo(2)
233
+ if asr > -100
234
+ bvn = a * Math.exp(asr) * (1 - c * (bs - as) * (1 - d * bs.quo(5)).quo(3) + c * d * as * as.quo(5))
235
+ end
236
+ if -hk < 100
237
+ b = Math.sqrt(bs)
238
+ bvn -= Math.exp(-hk.quo(2)) * Math.sqrt(twopi) * Distribution::Normal.cdf(-b.quo(a)) * b *
239
+ (1 - c * bs * (1 - d * bs.quo(5)).quo(3))
240
+ end
241
+
242
+ a = a.quo(2)
243
+ (1..lg).each do |i|
244
+ [-1, 1].each do |is|
245
+ xs = (a * (is * x[i][ng] + 1))**2
246
+ rs = Math.sqrt(1 - xs)
247
+ asr = -(bs / xs + hk).quo(2)
248
+ if asr > -100
249
+ bvn += a * w[i][ng] * Math.exp(asr) *
250
+ (Math.exp(-hk * (1 - rs).quo(2 * (1 + rs))) .quo(rs) - (1 + c * xs * (1 + d * xs)))
251
+ end
260
252
  end
261
253
  end
254
+ bvn = -bvn / twopi
262
255
  end
263
- bvn = -bvn/twopi
264
- end
265
-
266
- if ( r > 0 )
267
- bvn = bvn + Distribution::Normal.cdf(-[h,k].max)
268
- else
269
- bvn = -bvn
270
- if ( k > h )
271
- bvn = bvn + Distribution::Normal.cdf(k) - Distribution::Normal.cdf(h)
256
+
257
+ if r > 0
258
+ bvn += Distribution::Normal.cdf(-[h, k].max)
259
+ else
260
+ bvn = -bvn
261
+ if k > h
262
+ bvn = bvn + Distribution::Normal.cdf(k) - Distribution::Normal.cdf(h)
263
+ end
272
264
  end
273
265
  end
266
+ bvn
274
267
  end
275
- bvn
268
+ private :f, :sgn
276
269
  end
277
- private :f, :sgn
278
- end
279
270
  end
280
271
  end
281
272
  end