Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add rand::range and rand::shuffle as top-level helper functions #1488

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 93 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! # Quick Start
//!
//! To get you started quickly, the easiest and highest-level way to get
//! a random value is to use [`random()`]; alternatively you can use
//! a random value is to use [`random()`] or [`range()`]; alternatively you can use
//! [`thread_rng()`]. The [`Rng`] trait provides a useful API on all RNGs, while
//! the [`distr`] and [`seq`] modules provide further
//! functionality on top of RNGs.
Expand Down Expand Up @@ -111,9 +111,9 @@ pub use rng::{Fill, Rng};
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
use crate::distr::{Distribution, Standard};

/// Generates a random value using the thread-local random number generator.
/// Generate a random value using the thread-local random number generator.
///
/// This function is simply a shortcut for `thread_rng().gen()`:
/// This function is a shortcut for [`thread_rng().random()`](Rng::random):
///
/// - See [`ThreadRng`] for documentation of the generator and security
/// - See [`Standard`] for documentation of supported types and distributions
Expand Down Expand Up @@ -164,6 +164,71 @@ where
thread_rng().random()
}

/// Generate a random value in the given range using the thread-local random number generator.
///
/// This function is a shortcut for [`thread_rng().gen_range(range)`](Rng::gen_range).
///
/// # Examples
///
/// ```
/// let x = rand::range(1u8..=100);
/// println!("{}", x);
///
/// let y = rand::range(0f32..=1e9);
/// println!("{}", y);
/// ```
///
/// If you're calling `range()` in a loop, caching the generator as in the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean caching the distribution?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wording is copied from lines 135-136 above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the range is non-constant, caching the distribution helps. Either way, caching the result of rand::thread_rng also helps (slightly).

/// following example can increase performance.
///
/// ```
/// use rand::Rng;
///
/// let mut v = vec![1, 2, 3];
///
/// for x in v.iter_mut() {
/// *x = rand::range(1..=3)
TheIronBorn marked this conversation as resolved.
Show resolved Hide resolved
/// }
///
/// // can be made faster by caching thread_rng
///
/// let mut rng = rand::thread_rng();
///
/// for x in v.iter_mut() {
/// *x = rng.gen_range(1..=3)
/// }
/// ```
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
#[inline]
pub fn range<T, R>(range: R) -> T
where
T: distr::uniform::SampleUniform,
R: distr::uniform::SampleRange<T>,
{
thread_rng().gen_range(range)
}

/// Shuffle a mutable slice in place using the thread-local random number generator.
///
/// This function is a shortcut for [`slice.shuffle(&mut thread_rng())`](seq::SliceRandom::shuffle):
///
/// For slices of length `n`, complexity is `O(n)`.
/// The resulting permutation is picked uniformly from the set of all possible permutations.
///
/// # Example
///
/// ```
/// let mut y = [1, 2, 3, 4, 5];
/// println!("Unshuffled: {:?}", y);
/// rand::shuffle(&mut y);
/// println!("Shuffled: {:?}", y);
/// ```
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
#[inline]
pub fn shuffle<T>(slice: &mut [T]) {
seq::SliceRandom::shuffle(slice, &mut thread_rng());
}

#[cfg(test)]
mod test {
use super::*;
Expand All @@ -190,4 +255,29 @@ mod test {
(f32, (f64, (f64,))),
) = random();
}

#[test]
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
fn test_range() {
let _n: usize = range(42..=43);
let _f: f32 = range(42.0..43.0);
}

#[test]
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
fn test_shuffle() {
let mut array1 = [0; 100];
for (i, x) in array1.iter_mut().enumerate() {
*x = i;
}
let mut array2 = array1;
assert_eq!(array1, array2);
shuffle(&mut array1);
assert_ne!(array1, array2); // practically impossible without an RNG bug
shuffle(&mut array2);
assert_ne!(array1, array2); // same
array1.sort();
array2.sort();
assert_eq!(array1, array2);
}
}