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