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}