rand_distr/
unit_ball.rs

1// Copyright 2019 Developers of the Rand project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use num_traits::Float;
10use crate::{uniform::SampleUniform, Distribution, Uniform};
11use rand::Rng;
12
13/// Samples uniformly from the unit ball (surface and interior) in three
14/// dimensions.
15///
16/// Implemented via rejection sampling.
17///
18///
19/// # Example
20///
21/// ```
22/// use rand_distr::{UnitBall, Distribution};
23///
24/// let v: [f64; 3] = UnitBall.sample(&mut rand::thread_rng());
25/// println!("{:?} is from the unit ball.", v)
26/// ```
27#[derive(Clone, Copy, Debug)]
28#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
29pub struct UnitBall;
30
31impl<F: Float + SampleUniform> Distribution<[F; 3]> for UnitBall {
32    #[inline]
33    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [F; 3] {
34        let uniform = Uniform::new(F::from(-1.).unwrap(), F::from(1.).unwrap());
35        let mut x1;
36        let mut x2;
37        let mut x3;
38        loop {
39            x1 = uniform.sample(rng);
40            x2 = uniform.sample(rng);
41            x3 = uniform.sample(rng);
42            if x1 * x1 + x2 * x2 + x3 * x3 <= F::from(1.).unwrap() {
43                break;
44            }
45        }
46        [x1, x2, x3]
47    }
48}