@@ -65,6 +65,13 @@ impl Range<RangeInt<i32>> {
65
65
assert ! ( low < high, "Range::new called with `low >= high`" ) ;
66
66
Range { inner : RangeImpl :: new_inclusive ( low, high) }
67
67
}
68
+
69
+ /// Sample a single value uniformly from `[low, high)`.
70
+ /// Panics if `low >= high`.
71
+ pub fn sample_single < X : SampleRange , R : Rng +?Sized > ( low : X , high : X , rng : & mut R ) -> X {
72
+ assert ! ( low < high, "Range::sample_single called with low >= high" ) ;
73
+ X :: T :: sample_single ( low, high, rng)
74
+ }
68
75
}
69
76
70
77
impl < T : RangeImpl > Distribution < T :: X > for Range < T > {
@@ -118,8 +125,8 @@ pub trait SampleRange: PartialOrd+Sized {
118
125
/// let range = Range::new(low, high);
119
126
/// let x = range.sample(&mut thread_rng());
120
127
/// ```
121
- pub trait RangeImpl {
122
- /// The type sampled by this implementation (output type) .
128
+ pub trait RangeImpl : Sized {
129
+ /// The type sampled by this implementation.
123
130
type X : PartialOrd ;
124
131
125
132
/// Construct self, with inclusive lower bound and exclusive upper bound
@@ -137,6 +144,16 @@ pub trait RangeImpl {
137
144
138
145
/// Sample a value.
139
146
fn sample < R : Rng +?Sized > ( & self , rng : & mut R ) -> Self :: X ;
147
+
148
+ /// Sample a single value uniformly from a range with inclusive lower bound
149
+ /// and exclusive upper bound `[low, high)`.
150
+ /// Panics if `low >= high`.
151
+ fn sample_single < R : Rng +?Sized > ( low : Self :: X , high : Self :: X , rng : & mut R )
152
+ -> Self :: X
153
+ {
154
+ let range: Self = RangeImpl :: new ( low, high) ;
155
+ range. sample ( rng)
156
+ }
140
157
}
141
158
142
159
/// Implementation of `RangeImpl` for integer types.
@@ -246,9 +263,9 @@ macro_rules! range_int_impl {
246
263
loop {
247
264
let v: $u_large = Uniform . sample( rng) ;
248
265
if $use_mult {
249
- let ( high , low ) = v. wmul( range) ;
250
- if low <= zone {
251
- return self . low. wrapping_add( high as $ty) ;
266
+ let ( hi , lo ) = v. wmul( range) ;
267
+ if lo <= zone {
268
+ return self . low. wrapping_add( hi as $ty) ;
252
269
}
253
270
} else {
254
271
if v <= zone {
@@ -261,6 +278,37 @@ macro_rules! range_int_impl {
261
278
Uniform . sample( rng)
262
279
}
263
280
}
281
+
282
+ fn sample_single<R : Rng +?Sized >( low: Self :: X , high: Self :: X , rng: & mut R ) -> Self :: X {
283
+ let range = ( high as $u_large)
284
+ . wrapping_sub( low as $u_large) ;
285
+ let zone =
286
+ if :: core:: $unsigned:: MAX <= :: core:: u16 :: MAX as $unsigned {
287
+ // Using a modulus is faster than the approximation for
288
+ // i8 and i16. I suppose we trade the cost of one
289
+ // modulus for near-perfect branch prediction.
290
+ let unsigned_max: $u_large = :: core:: $u_large:: MAX ;
291
+ let ints_to_reject = ( unsigned_max - range + 1 ) % range;
292
+ unsigned_max - ints_to_reject
293
+ } else {
294
+ // conservative but fast approximation
295
+ range << range. leading_zeros( )
296
+ } ;
297
+
298
+ loop {
299
+ let v: $u_large = Uniform . sample( rng) ;
300
+ if $use_mult {
301
+ let ( hi, lo) = v. wmul( range) ;
302
+ if lo <= zone {
303
+ return low. wrapping_add( hi as $ty) ;
304
+ }
305
+ } else {
306
+ if v <= zone {
307
+ return low. wrapping_add( ( v % range) as $ty) ;
308
+ }
309
+ }
310
+ }
311
+ }
264
312
}
265
313
}
266
314
}
0 commit comments