jandom/
lib.rs

1//! Pseudorandom number generator implemented with the same algorithm and parameters as
2//! `java.util.Random`.
3//!
4//! This crate has feature parity with the Java 17 implementation of `Random`. The crate
5//! includes the sources for fdlibm (freely distributable libm) which is used by `StrictMath`
6//! in Java.
7
8use std::fmt;
9use std::sync::atomic::{AtomicI64, Ordering};
10use std::sync::{Arc, Mutex};
11
12#[cfg(test)]
13mod tests;
14
15extern "C" {
16    fn __ieee754_sqrt(x: f64) -> f64;
17    fn __ieee754_log(x: f64) -> f64;
18}
19
20const MULTIPLIER: i64 = 0x0005_deec_e66d;
21const INCREMENT: i64 = 0xb;
22const MASK: i64 = (1 << 48) - 1;
23
24/// A pseudorandom number generator
25pub struct Random {
26    state: AtomicI64,
27    next_next_gaussian: Arc<Mutex<Option<f64>>>,
28}
29
30impl Random {
31    /// Creates a new random number generator using a single [i64] seed.
32    ///
33    /// This has the same effect as calling the constructor with seed param in Java.
34    #[must_use]
35    pub fn new(seed: i64) -> Self {
36        Self {
37            state: AtomicI64::new(Self::initalize_state(seed)),
38            next_next_gaussian: Arc::new(Mutex::new(None)),
39        }
40    }
41
42    /// Calculates the the initial state from a seed
43    const fn initalize_state(seed: i64) -> i64 {
44        seed ^ MULTIPLIER & MASK
45    }
46
47    /// Advances the RNG by one and returns random bits.
48    ///
49    /// # Panics
50    ///
51    /// Panics if `bits` is bigger than 32
52    fn next(&mut self, bits: u8) -> i32 {
53        assert!(bits <= 32, "can't return more than 32 random bits");
54
55        let mut previous_state = self.state.load(Ordering::Acquire);
56        loop {
57            let new_state = previous_state
58                .wrapping_mul(MULTIPLIER)
59                .wrapping_add(INCREMENT)
60                & MASK;
61            // Using weak since it allows optimizations on certain (e.g. ARM) architectures
62            match self.state.compare_exchange_weak(
63                previous_state,
64                new_state,
65                Ordering::AcqRel,
66                Ordering::Relaxed,
67            ) {
68                Ok(_) => return (new_state >> (48 - bits)) as i32,
69                Err(state) => previous_state = state,
70            }
71        }
72    }
73
74    /// Returns the next pseudorandom, uniformly distributed [i32] value from this random
75    /// number generator's sequence. The general contract of `next_i32` is that one [i32] value
76    /// is pseudorandomly generated and returned. All 2^32 possible [i32] values are produced
77    /// with (approximately) equal probability.
78    pub fn next_i32(&mut self) -> i32 {
79        self.next(32)
80    }
81
82    /// Returns a pseudorandom, uniformly distributed [i32] value between 0 (inclusive) and
83    /// the specified value (exclusive), drawn from this random number generator's sequence.
84    /// The general contract of `next_i32_bounded` is that one [i32] value in the specified range is
85    /// pseudorandomly generated and returned. All bound possible [i32] values are produced
86    /// with (approximately) equal probability.
87    ///
88    /// # Panics
89    ///
90    /// Panics if bound is zero or negative
91    pub fn next_i32_bounded(&mut self, bound: i32) -> i32 {
92        assert!(bound > 0, "bound must be positive");
93
94        // bound is power of 2
95        if (bound & -bound) == bound {
96            let bound_i64 = i64::from(bound);
97            let next_i64 = i64::from(self.next(31));
98            let result = bound_i64.wrapping_mul(next_i64) >> 31;
99            result as i32
100        } else {
101            loop {
102                let bits = self.next(31);
103                let val = bits % bound;
104                if !bits.wrapping_sub(val).wrapping_add(bound.wrapping_sub(1)) < 0 {
105                    return val;
106                }
107            }
108        }
109    }
110
111    /// Returns the next pseudorandom, uniformly distributed long value from this random
112    /// number generator's sequence. The general contract of `next_i64` is that one long
113    /// value is pseudorandomly generated and returned.
114    pub fn next_i64(&mut self) -> i64 {
115        (i64::from(self.next(32)) << 32) + i64::from(self.next(32))
116    }
117
118    /// Returns the next pseudorandom, uniformly distributed boolean value from this
119    /// random number generator's sequence. The general contract of `next_bool` is that
120    /// one boolean value is pseudorandomly generated and returned. The values true and
121    /// false are produced with (approximately) equal probability.
122    pub fn next_bool(&mut self) -> bool {
123        self.next(1) != 0
124    }
125
126    /// Returns the next pseudorandom, uniformly distributed [f32] value between 0.0 and
127    /// 1.0 from this random number generator's sequence.
128    ///
129    /// The general contract of `next_f32` is that one [f32] value, chosen (approximately)
130    /// uniformly from the range 0.0f (inclusive) to 1.0f (exclusive), is pseudorandomly
131    /// generated and returned. All 2^24 possible [f32] values of the form m * 2^-24, where
132    /// m is a positive integer less than 2^24, are produced with (approximately) equal
133    /// probability.
134    pub fn next_f32(&mut self) -> f32 {
135        self.next(24) as f32 / ((1 << 24) as f32)
136    }
137
138    /// Returns the next pseudorandom, uniformly distributed [f64] value between 0.0 and
139    /// 1.0 from this random number generator's sequence.
140    ///
141    /// The general contract of `next_f64` is that one [f64] value, chosen (approximately)
142    /// uniformly from the range 0.0 (inclusive) to 1.0 (exclusive), is pseudorandomly
143    /// generated and returned.
144    pub fn next_f64(&mut self) -> f64 {
145        (((i64::from(self.next(26)) << 27) + i64::from(self.next(27))) as f64)
146            / ((1_i64 << 53) as f64)
147    }
148
149    /// Generates random bytes and places them into a user-supplied i8 slice. The
150    /// number of random bytes produced is equal to the length of the slice.
151    pub fn next_bytes(&mut self, bytes: &mut [i8]) {
152        let max = bytes.len() & !0x3;
153
154        for i in (0..max).step_by(4) {
155            let random = self.next(32);
156            bytes[i] = random as i8;
157            bytes[i + 1] = (random >> 8) as i8;
158            bytes[i + 2] = (random >> 16) as i8;
159            bytes[i + 3] = (random >> 24) as i8;
160        }
161        if max < bytes.len() {
162            let mut random = self.next(32);
163            for byte in bytes.iter_mut().skip(max) {
164                *byte = random as i8;
165                random >>= 8;
166            }
167        }
168    }
169
170    /// Returns the next pseudorandom, Gaussian ("normally") distributed [f64] value with
171    /// mean 0.0 and standard deviation 1.0 from this random number generator's sequence.
172    ///
173    /// The general contract of `next_gaussian` is that one [f64] value, chosen from
174    /// (approximately) the usual normal distribution with mean 0.0 and standard deviation
175    /// 1.0, is pseudorandomly generated and returned.
176    pub fn next_gaussian(&mut self) -> f64 {
177        let mutex = self.next_next_gaussian.clone();
178        let mut next_gaussian = mutex.lock().unwrap();
179        if let Some(gaussian) = *next_gaussian {
180            *next_gaussian = None;
181            gaussian
182        } else {
183            let mut s;
184            let mut v1;
185            let mut v2;
186            loop {
187                v1 = 2_f64 * self.next_f64() - 1_f64;
188                v2 = 2_f64 * self.next_f64() - 1_f64;
189                s = v1 * v1 + v2 * v2;
190                if !(s >= 1_f64 || s == 0_f64) {
191                    break;
192                }
193            }
194            let multiplier;
195            // SAFETY: `sqrt` and `log` are C functions which are safe to call with any
196            // arguments.
197            unsafe {
198                multiplier = __ieee754_sqrt(-2_f64 * __ieee754_log(s) / s);
199            }
200            *next_gaussian = Some(v2 * multiplier);
201            v1 * multiplier
202        }
203    }
204}
205
206/// Implemented custom Debug in order to prevent users from leaking the internal state
207impl fmt::Debug for Random {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        write!(
210            f,
211            "Random number generator implemented with the same algorithm as java.util.Random"
212        )
213    }
214}
215
216static SEED_UNIQUFIER: AtomicI64 = AtomicI64::new(8_682_522_807_148_012);
217
218/// The default implementation represents the Java Random constructor with no params.
219impl Default for Random {
220    #[inline]
221    fn default() -> Self {
222        use std::time::{SystemTime, UNIX_EPOCH};
223        const MULTIPLIER: i64 = 1181783497276652981;
224
225        let mut current = SEED_UNIQUFIER.load(Ordering::Acquire);
226        loop {
227            let new = current.wrapping_mul(MULTIPLIER);
228            match SEED_UNIQUFIER.compare_exchange_weak(
229                current,
230                new,
231                Ordering::AcqRel,
232                Ordering::Relaxed,
233            ) {
234                Ok(_) => {
235                    let elapsed = SystemTime::now()
236                        .duration_since(UNIX_EPOCH)
237                        .expect("SystemTime returned value earlier than UNIX_EPOCH");
238                    return Self::new(new ^ (elapsed.as_nanos() as i64));
239                }
240                Err(uniquifier) => current = uniquifier,
241            }
242        }
243    }
244}