Skip to content

Commit 7ad2090

Browse files
committed
Add uniform distribs for u32 and usize
1 parent 4b57d3b commit 7ad2090

File tree

1 file changed

+60
-8
lines changed

1 file changed

+60
-8
lines changed

core/src/math/rand.rs

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ pub trait Distrib: Clone {
3535
/// ```
3636
/// use retrofire_core::math::rand::*;
3737
///
38-
/// // Simulate rolling a six-sided die
38+
/// // Simulate rolling a six-sided die three times
3939
/// let rng = &mut DefaultRng::default();
40-
/// let mut iter = Uniform(1..7).samples(rng);
40+
/// let mut iter = Uniform(1u32..7).samples(rng);
4141
///
4242
/// assert_eq!(iter.next(), Some(3));
4343
/// assert_eq!(iter.next(), Some(2));
@@ -217,7 +217,7 @@ impl Default for Xorshift64 {
217217
// Local trait impls
218218
//
219219

220-
/// Uniformly distributed integers.
220+
/// Uniformly distributed signed integers.
221221
impl Distrib for Uniform<i32> {
222222
type Sample = i32;
223223

@@ -228,18 +228,70 @@ impl Distrib for Uniform<i32> {
228228
/// use retrofire_core::math::rand::*;
229229
/// let rng = &mut DefaultRng::default();
230230
///
231-
/// // Simulate rolling a six-sided die
232-
/// let mut iter = Uniform(1..7).samples(rng);
233-
/// assert_eq!(iter.next(), Some(3));
234-
/// assert_eq!(iter.next(), Some(2));
231+
///
232+
/// let mut iter = Uniform(-5i32..6).samples(rng);
233+
/// assert_eq!(iter.next(), Some(0));
235234
/// assert_eq!(iter.next(), Some(4));
235+
/// assert_eq!(iter.next(), Some(5));
236236
/// ```
237237
fn sample(&self, rng: &mut DefaultRng) -> i32 {
238238
let bits = rng.next_bits() as i32;
239239
// TODO rem introduces slight bias
240240
bits.rem_euclid(self.0.end - self.0.start) + self.0.start
241241
}
242242
}
243+
/// Uniformly distributed unsigned integers.
244+
impl Distrib for Uniform<u32> {
245+
type Sample = u32;
246+
247+
/// Returns a uniformly distributed `u32` in the range.
248+
///
249+
/// # Examples
250+
/// ```
251+
/// use retrofire_core::math::rand::*;
252+
/// let rng = &mut DefaultRng::from_seed(1234);
253+
///
254+
/// // Simulate rolling a six-sided die
255+
/// let mut rolls: Vec<_> = Uniform(1u32..7)
256+
/// .samples(rng)
257+
/// .take(6)
258+
/// .collect();
259+
/// assert_eq!(rolls, [2, 4, 6, 6, 3, 1]);
260+
/// ```
261+
fn sample(&self, rng: &mut DefaultRng) -> u32 {
262+
let bits = rng.next_bits() as u32;
263+
// TODO rem introduces slight bias
264+
bits.rem_euclid(self.0.end - self.0.start) + self.0.start
265+
}
266+
}
267+
268+
/// Uniformly distributed indices.
269+
impl Distrib for Uniform<usize> {
270+
type Sample = usize;
271+
272+
/// Returns a uniformly distributed `usize` in the range.
273+
///
274+
/// # Examples
275+
/// ```
276+
/// use retrofire_core::math::rand::*;
277+
/// let rng = &mut DefaultRng::default();
278+
///
279+
/// // Randomly sample elements from a list (with replacement)
280+
/// let beverages = ["water", "tea", "coffee", "Coke", "Red Bull"];
281+
/// let mut x: Vec<_> = Uniform(0..beverages.len())
282+
/// .samples(rng)
283+
/// .take(3)
284+
/// .map(|i| beverages[i])
285+
/// .collect();
286+
///
287+
/// assert_eq!(x, ["water", "tea", "Red Bull"]);
288+
/// ```
289+
fn sample(&self, rng: &mut DefaultRng) -> usize {
290+
let bits = rng.next_bits() as usize;
291+
// TODO rem introduces slight bias
292+
bits.rem_euclid(self.0.end - self.0.start) + self.0.start
293+
}
294+
}
243295

244296
/// Uniformly distributed floats.
245297
impl Distrib for Uniform<f32> {
@@ -491,7 +543,7 @@ mod tests {
491543

492544
#[test]
493545
fn uniform_i32() {
494-
let dist = Uniform(-123..456);
546+
let dist = Uniform(-123i32..456);
495547
for r in dist.samples(&mut rng()).take(COUNT) {
496548
assert!(-123 <= r && r < 456);
497549
}

0 commit comments

Comments
 (0)