@@ -46,6 +46,13 @@ impl Binomial {
46
46
}
47
47
}
48
48
49
+ /// Convert a `f64` to an `i64`, panicing on overflow.
50
+ // In the future (Rust 1.34), this might be replaced with `TryFrom`.
51
+ fn f64_to_i64 ( x : f64 ) -> i64 {
52
+ assert ! ( x < ( :: std:: i64 :: MAX as f64 ) ) ;
53
+ x as i64
54
+ }
55
+
49
56
impl Distribution < u64 > for Binomial {
50
57
fn sample < R : Rng + ?Sized > ( & self , rng : & mut R ) -> u64 {
51
58
// Handle these values directly.
@@ -105,7 +112,7 @@ impl Distribution<u64> for Binomial {
105
112
let np = n * p;
106
113
let npq = np * q;
107
114
let f_m = np + p;
108
- let m = f_m as i64 ;
115
+ let m = f64_to_i64 ( f_m) ;
109
116
// radius of triangle region, since height=1 also area of region
110
117
let p1 = ( 2.195 * npq. sqrt ( ) - 4.6 * q) . floor ( ) + 0.5 ;
111
118
// tip of triangle
@@ -138,7 +145,7 @@ impl Distribution<u64> for Binomial {
138
145
let u = rng. gen_range ( 0. , p4) ;
139
146
let mut v = rng. gen_range ( 0. , 1. ) ;
140
147
if !( u > p1) {
141
- y = ( x_m - p1 * v + u) as i64 ;
148
+ y = f64_to_i64 ( x_m - p1 * v + u) ;
142
149
break ;
143
150
}
144
151
@@ -150,19 +157,19 @@ impl Distribution<u64> for Binomial {
150
157
if v > 1. {
151
158
continue ;
152
159
} else {
153
- y = x as i64 ;
160
+ y = f64_to_i64 ( x ) ;
154
161
}
155
162
} else if !( u > p3) {
156
163
// Step 3: Region 3, left exponential tail.
157
- y = ( x_l + v. ln ( ) / lambda_l) as i64 ;
164
+ y = f64_to_i64 ( x_l + v. ln ( ) / lambda_l) ;
158
165
if y < 0 {
159
166
continue ;
160
167
} else {
161
168
v *= ( u - p2) * lambda_l;
162
169
}
163
170
} else {
164
171
// Step 4: Region 4, right exponential tail.
165
- y = ( x_r - v. ln ( ) / lambda_r) as i64 ;
172
+ y = f64_to_i64 ( x_r - v. ln ( ) / lambda_r) ;
166
173
if y > 0 && ( y as u64 ) > self . n {
167
174
continue ;
168
175
} else {
@@ -222,8 +229,8 @@ impl Distribution<u64> for Binomial {
222
229
// Step 5.3: Final acceptance/rejection test.
223
230
let x1 = ( y + 1 ) as f64 ;
224
231
let f1 = ( m + 1 ) as f64 ;
225
- let z = ( ( n as i64 ) + 1 - m) as f64 ;
226
- let w = ( ( n as i64 ) - y + 1 ) as f64 ;
232
+ let z = ( f64_to_i64 ( n ) + 1 - m) as f64 ;
233
+ let w = ( f64_to_i64 ( n ) - y + 1 ) as f64 ;
227
234
228
235
fn stirling ( a : f64 ) -> f64 {
229
236
let a2 = a * a;
@@ -233,6 +240,11 @@ impl Distribution<u64> for Binomial {
233
240
if alpha > x_m * ( f1 / x1) . ln ( )
234
241
+ ( n - ( m as f64 ) + 0.5 ) * ( z / w) . ln ( )
235
242
+ ( ( y - m) as f64 ) * ( w * p / ( x1 * q) ) . ln ( )
243
+ // We use the signs from the GSL implementation, which are
244
+ // different than the ones in the reference. According to
245
+ // the GSL authors, the new signs were verified to be
246
+ // correct by one of the original designers of the
247
+ // algorithm.
236
248
+ stirling ( f1) + stirling ( z) - stirling ( x1) - stirling ( w)
237
249
{
238
250
continue ;
0 commit comments