]> git.proxmox.com Git - rustc.git/blob - vendor/rand-0.7.3/src/distributions/unit_sphere.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / vendor / rand-0.7.3 / src / distributions / unit_sphere.rs
1 // Copyright 2018 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
9 #![allow(deprecated)]
10 #![allow(clippy::all)]
11
12 use crate::distributions::{Distribution, Uniform};
13 use crate::Rng;
14
15 /// Samples uniformly from the surface of the unit sphere in three dimensions.
16 ///
17 /// Implemented via a method by Marsaglia[^1].
18 ///
19 /// [^1]: Marsaglia, George (1972). [*Choosing a Point from the Surface of a
20 /// Sphere.*](https://doi.org/10.1214/aoms/1177692644)
21 /// Ann. Math. Statist. 43, no. 2, 645--646.
22 #[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
23 #[derive(Clone, Copy, Debug)]
24 pub struct UnitSphereSurface;
25
26 impl UnitSphereSurface {
27 /// Construct a new `UnitSphereSurface` distribution.
28 #[inline]
29 pub fn new() -> UnitSphereSurface {
30 UnitSphereSurface
31 }
32 }
33
34 impl Distribution<[f64; 3]> for UnitSphereSurface {
35 #[inline]
36 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 3] {
37 let uniform = Uniform::new(-1., 1.);
38 loop {
39 let (x1, x2) = (uniform.sample(rng), uniform.sample(rng));
40 let sum = x1 * x1 + x2 * x2;
41 if sum >= 1. {
42 continue;
43 }
44 let factor = 2. * (1.0_f64 - sum).sqrt();
45 return [x1 * factor, x2 * factor, 1. - 2. * sum];
46 }
47 }
48 }
49
50 #[cfg(test)]
51 mod tests {
52 use super::UnitSphereSurface;
53 use crate::distributions::Distribution;
54
55 /// Assert that two numbers are almost equal to each other.
56 ///
57 /// On panic, this macro will print the values of the expressions with their
58 /// debug representations.
59 macro_rules! assert_almost_eq {
60 ($a:expr, $b:expr, $prec:expr) => {
61 let diff = ($a - $b).abs();
62 if diff > $prec {
63 panic!(format!(
64 "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \
65 (left: `{}`, right: `{}`)",
66 diff, $prec, $a, $b
67 ));
68 }
69 };
70 }
71
72 #[test]
73 fn norm() {
74 let mut rng = crate::test::rng(1);
75 let dist = UnitSphereSurface::new();
76 for _ in 0..1000 {
77 let x = dist.sample(&mut rng);
78 assert_almost_eq!(x[0] * x[0] + x[1] * x[1] + x[2] * x[2], 1., 1e-15);
79 }
80 }
81
82 #[test]
83 fn value_stability() {
84 let mut rng = crate::test::rng(2);
85 let expected = [
86 [0.03247542860231647, -0.7830477442152738, 0.6211131755296027],
87 [-0.09978440840914075, 0.9706650829833128, -0.21875184231323952],
88 [0.2735582468624679, 0.9435374242279655, -0.1868234852870203],
89 ];
90 let samples = [
91 UnitSphereSurface.sample(&mut rng),
92 UnitSphereSurface.sample(&mut rng),
93 UnitSphereSurface.sample(&mut rng),
94 ];
95 assert_eq!(samples, expected);
96 }
97 }