Skip to content

Commit 634d4cb

Browse files
committed
Documentation: revise doc of uniform module
1 parent 5d10661 commit 634d4cb

File tree

2 files changed

+73
-42
lines changed

2 files changed

+73
-42
lines changed

src/distributions/uniform.rs

Lines changed: 66 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,49 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! A distribution uniformly generating numbers within a given range.
11+
//! A distribution uniformly sampling numbers within a given range.
1212
//!
13-
//! [`Uniform`] is the standard distribution to sample from uniform ranges, and
14-
//! forms the basis for [`Rng::gen_range`].
13+
//! [`Uniform`] is the standard distribution to sample uniformly from a range;
14+
//! e.g. `Uniform::new_inclusive(1, 6)` can sample integers from 1 to 6, like a
15+
//! standard die. [`Rng::gen_range`] simply uses [`Uniform::sample_single`],
16+
//! thus supports any type supported by [`Uniform`].
1517
//!
16-
//! To make sampling from a uniform range also possible for custom types
17-
//! [`Uniform`] depends on the [`SampleUniform`] and [`UniformImpl`] traits.
18+
//! This distribution is provided with support for several primitive types
19+
//! (all integer and floating-point types) as well as `std::time::Duration`,
20+
//! and supports extension to user-defined types via a type-specific *back-end*
21+
//! implementation.
1822
//!
19-
//! Rand comes with an implementation of [`Uniform`] for sampling from integers
20-
//! and from floats, via [`UniformInt`] and [`UniformFloat`]. They are mostly an
21-
//! implementation detail and should not be used directly, but may be useful
22-
//! when you want to reuse the logic to implement range sampling for a custom
23-
//! type.
23+
//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the
24+
//! back-ends supporting sampling from primitive integer and floating-point
25+
//! ranges as well as from `std::time::Duration`; these types do not normally
26+
//! need to be used directly (unless implementing a derived back-end).
2427
//!
25-
//! Also implemented is a distribution for `Duration`.
28+
//! # Example usage
2629
//!
27-
//! # Implementing `Uniform` for a custom type
30+
//! ```
31+
//! use rand::{Rng, thread_rng};
32+
//! use rand::distributions::Uniform;
33+
//!
34+
//! let mut rng = thread_rng();
35+
//! let side = Uniform::new(-10.0, 10.0);
36+
//!
37+
//! // sample between 1 and 10 points
38+
//! for _ in 0..rng.gen_range(1, 11) {
39+
//! // sample a point from the square with sides -10 - 10 in two dimensions
40+
//! let (x, y) = (rng.sample(side), rng.sample(side));
41+
//! println!("Point: {}, {}", x, y);
42+
//! }
43+
//! ```
2844
//!
29-
//! For the type you will need to create a struct that holds the lower and upper
30-
//! bounds of the range, and possibly some helper variables. The struct has to
31-
//! implement the [`UniformImpl`] trait to do the uniform range sampling.
45+
//! # Extending `Uniform` to support a custom type
3246
//!
33-
//! Additionally the type must implement the [`SampleUniform`] trait, which
34-
//! doesn't do anything but point to the struct implementing [`UniformImpl`].
47+
//! To extend [`Uniform`] to support your own types, write a back-end which
48+
//! implements the [`UniformImpl`] trait, then implement the [`SampleUniform`]
49+
//! helper trait to "register" your back-end. See the `MyF32` example below.
3550
//!
36-
//! ## Examples
51+
//! At a minimum, the back-end needs to store any parameters needed for sampling
52+
//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`.
53+
//! The example below merely wraps another back-end.
3754
//!
3855
//! ```
3956
//! use rand::{Rng, thread_rng};
@@ -73,11 +90,13 @@
7390
//! ```
7491
//!
7592
//! [`Uniform`]: struct.Uniform.html
93+
//! [`Uniform::sample_single`]: struct.Uniform.html#method.sample_single
7694
//! [`Rng::gen_range`]: ../../trait.Rng.html#method.gen_range
7795
//! [`SampleUniform`]: trait.SampleUniform.html
7896
//! [`UniformImpl`]: trait.UniformImpl.html
7997
//! [`UniformInt`]: struct.UniformInt.html
8098
//! [`UniformFloat`]: struct.UniformFloat.html
99+
//! [`UniformDuration`]: struct.UniformDuration.html
81100
82101
#[cfg(feature = "std")]
83102
use std::time::Duration;
@@ -88,26 +107,30 @@ use distributions::float::IntoFloat;
88107

89108
/// Sample values uniformly between two bounds.
90109
///
91-
/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a `Uniform`
92-
/// distribution sampling from the closed-open and the closed (inclusive) range.
93-
/// Some preparations are performed up front to make sampling values faster.
94-
/// [`Uniform::sample_single`] is optimized for sampling values once or only a
95-
/// limited number of times from a range.
110+
/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform
111+
/// distribution sampling from the given range; these functions may do extra
112+
/// work up front to make sampling of multiple values faster.
96113
///
97-
/// If you need to sample many values from a range, consider using [`new`] or
98-
/// [`new_inclusive`]. This is also the best choice if the range is constant,
99-
/// because then the preparations can be evaluated at compile-time.
100-
/// Otherwise [`sample_single`] may be the best choice.
114+
/// [`Uniform::sample_single`] instead samples directly from the given range,
115+
/// and (depending on the back-end) may be faster when sampling a very small
116+
/// number of values or only a single value from this range.
101117
///
102-
/// Sampling uniformly from a range can be surprisingly complicated to be both
103-
/// generic and correct. Consider for example edge cases like `low = 0u8`,
104-
/// `high = 170u8`, for which a naive modulo operation would return numbers less
105-
/// than 85 with double the probability to those greater than 85.
118+
/// When sampling from a constant range, many calculations can happen at
119+
/// compile-time and all methods should be fast; for floating-point ranges and
120+
/// the full range of integer types this should have comparable performance to
121+
/// the `Standard` distribution.
106122
///
107-
/// Types should attempt to sample in `[low, high)` for `Uniform::new(low, high)`,
108-
/// i.e., excluding `high`, but this may be very difficult. All the primitive
109-
/// integer types satisfy this property, and the float types normally satisfy
110-
/// it, but rounding may mean `high` can occur.
123+
/// Steps are taken to avoid bias which might be present in naive
124+
/// implementations; for example `rng.gen::<u8>() % 170` samples from the range
125+
/// `[0, 169]` but is twice as likely to select numbers less than 85 than other
126+
/// values. Further, the implementations here give more weight to the high-bits
127+
/// generated by the RNG than the low bits, since with some RNGs the low-bits
128+
/// are of lower quality than the high bits.
129+
///
130+
/// Implementations should attempt to sample in `[low, high)` for
131+
/// `Uniform::new(low, high)`, i.e., excluding `high`, but this may be very
132+
/// difficult. All the primitive integer types satisfy this property, and the
133+
/// float types normally satisfy it, but rounding may mean `high` can occur.
111134
///
112135
/// # Example
113136
///
@@ -184,8 +207,12 @@ pub trait SampleUniform: PartialOrd+Sized {
184207
/// See the [module documentation] on how to implement [`Uniform`] range
185208
/// sampling for a custom type.
186209
///
210+
/// Implementation of [`sample_single`] is optional, and is only useful when
211+
/// the implementation can be faster than `Self::new(low, high).sample(rng)`.
212+
///
187213
/// [module documentation]: index.html
188214
/// [`Uniform`]: struct.Uniform.html
215+
/// [`sample_single`]: struct.UniformImpl.html#method.sample_single
189216
pub trait UniformImpl: Sized {
190217
/// The type sampled by this implementation.
191218
type X: PartialOrd;
@@ -200,8 +227,8 @@ pub trait UniformImpl: Sized {
200227
/// Construct self, with inclusive bounds `[low, high]`.
201228
///
202229
/// Usually users should not call this directly but instead use
203-
/// `Uniform::new_inclusive`, which asserts that `low < high` before calling
204-
/// this.
230+
/// `Uniform::new_inclusive`, which asserts that `low <= high` before
231+
/// calling this.
205232
fn new_inclusive(low: Self::X, high: Self::X) -> Self;
206233

207234
/// Sample a value.
@@ -226,7 +253,7 @@ pub trait UniformImpl: Sized {
226253
}
227254
}
228255

229-
/// Implementation of [`UniformImpl`] for integer types.
256+
/// The back-end implementing [`UniformImpl`] for integer types.
230257
///
231258
/// Unless you are implementing [`UniformImpl`] for your own type, this type
232259
/// should not be used directly, use [`Uniform`] instead.
@@ -483,7 +510,7 @@ wmul_impl_usize! { u64 }
483510

484511

485512

486-
/// Implementation of [`UniformImpl`] for float types.
513+
/// The back-end implementing [`UniformImpl`] for floating-point types.
487514
///
488515
/// Unless you are implementing [`UniformImpl`] for your own type, this type
489516
/// should not be used directly, use [`Uniform`] instead.

src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,11 @@ pub trait Rng: RngCore {
325325
/// `low` and exclusive of `high`.
326326
///
327327
/// This is a convenience wrapper around
328-
/// `distributions::Uniform::sample_single`. If this function will be called
328+
/// [`Uniform::sample_single`]. If this function will be called
329329
/// repeatedly with the same arguments, it will likely be faster to
330-
/// construct a `Uniform` distribution object and sample from that; this
330+
/// construct a [`Uniform`] distribution object and sample from that; this
331331
/// allows amortization of the computations that allow for perfect
332-
/// uniformity within the `Uniform::new` constructor.
332+
/// uniformity within the [`Uniform::new`] constructor.
333333
///
334334
/// # Panics
335335
///
@@ -346,6 +346,10 @@ pub trait Rng: RngCore {
346346
/// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64);
347347
/// println!("{}", m);
348348
/// ```
349+
///
350+
/// [`Uniform`]: distributions/uniform/struct.Uniform.html
351+
/// [`Uniform::new`]: distributions/uniform/struct.Uniform.html#method.new
352+
/// [`Uniform::sample_single`]: distributions/uniform/struct.Uniform.html#method.sample_single
349353
fn gen_range<T: PartialOrd + SampleUniform>(&mut self, low: T, high: T) -> T {
350354
Uniform::sample_single(low, high, self)
351355
}

0 commit comments

Comments
 (0)