oorandom/
lib.rs

1//! A tiny, robust PRNG implementation.
2//!
3//! More specifically, it implements a single GOOD PRNG algorithm,
4//! which is currently a permuted congruential generator.  It has two
5//! implementations, one that returns `u32` and one that returns
6//! `u64`.  It also has functions that return floats or integer
7//! ranges.  And that's it.  What more do you need?
8//!
9//! For more info on PCG generators, see http://www.pcg-random.org/
10//!
11//! This was designed as a minimalist utility for video games.  No
12//! promises are made about its quality, and if you use it for
13//! cryptography you will get what you deserve.
14//!
15//! Works with `#![no_std]`, has no global state, no dependencies
16//! apart from some in the unit tests, and is generally neato.
17
18#![forbid(unsafe_code)]
19#![forbid(missing_docs)]
20#![forbid(missing_debug_implementations)]
21#![forbid(unused_results)]
22#![no_std]
23use core::ops::Range;
24
25/// A PRNG producing a 32-bit output.
26///
27/// The current implementation is `PCG-XSH-RR`.
28#[derive(Copy, Clone, Debug, PartialEq, Eq)]
29pub struct Rand32 {
30    state: u64,
31    inc: u64,
32}
33
34impl Rand32 {
35    /// The default value for `increment`.
36    /// This is basically arbitrary, it comes from the
37    /// PCG reference C implementation:
38    /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L284
39    pub const DEFAULT_INC: u64 = 1442695040888963407;
40
41    /// This is the number that you have to Really Get Right.
42    ///
43    /// The value used here is from the PCG C implementation:
44    /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L278
45    pub(crate) const MULTIPLIER: u64 = 6364136223846793005;
46
47    /// Creates a new PRNG with the given seed and a default increment.
48    pub fn new(seed: u64) -> Self {
49        Self::new_inc(seed, Self::DEFAULT_INC)
50    }
51
52    /// Creates a new PRNG.  The two inputs, `seed` and `increment`,
53    /// determine what you get; `increment` basically selects which
54    /// sequence of all those possible the PRNG will produce, and the
55    /// `seed` selects where in that sequence you start.
56    ///
57    /// Both are arbitrary; increment must be an odd number but this
58    /// handles that for you
59    pub fn new_inc(seed: u64, increment: u64) -> Self {
60        let mut rng = Self {
61            state: 0,
62            inc: increment.wrapping_shl(1) | 1,
63        };
64        // This initialization song-and-dance is a little odd,
65        // but seems to be just how things go.
66        let _ = rng.rand_u32();
67        rng.state = rng.state.wrapping_add(seed);
68        let _ = rng.rand_u32();
69        rng
70    }
71
72    /// Returns the internal state of the PRNG.  This allows
73    /// you to save a PRNG and create a new one that will resume
74    /// from the same spot in the sequence.
75    pub fn state(&self) -> (u64, u64) {
76        (self.state, self.inc)
77    }
78
79    /// Creates a new PRNG from a saved state from `Rand32::state()`.
80    /// This is NOT quite the same as `new_inc()` because `new_inc()` does
81    /// a little extra setup work to initialize the state.
82    pub fn from_state(state: (u64, u64)) -> Self {
83        let (state, inc) = state;
84        Self { state, inc }
85    }
86
87    /// Produces a random `u32` in the range `[0, u32::MAX]`.
88    pub fn rand_u32(&mut self) -> u32 {
89        let oldstate: u64 = self.state;
90        self.state = oldstate
91            .wrapping_mul(Self::MULTIPLIER)
92            .wrapping_add(self.inc);
93        let xorshifted: u32 = (((oldstate >> 18) ^ oldstate) >> 27) as u32;
94        let rot: u32 = (oldstate >> 59) as u32;
95        xorshifted.rotate_right(rot)
96    }
97
98    /// Produces a random `i32` in the range `[i32::MIN, i32::MAX]`.
99    pub fn rand_i32(&mut self) -> i32 {
100        self.rand_u32() as i32
101    }
102
103    /// Produces a random `f32` in the range `[0.0, 1.0)`.
104    pub fn rand_float(&mut self) -> f32 {
105        // This impl was taken more or less from `rand`, see
106        // <https://docs.rs/rand/0.7.0/src/rand/distributions/float.rs.html#104-117>
107        // Note that we use f32::MANTISSA_DIGITS = 24, where that impl passes the
108        // number as an input to the macro and uses 23 so needs a +1.
109        // See https://todo.sr.ht/~icefox/oorandom/9
110        // There MAY be better ways to do this, see:
111        // https://mumble.net/~campbell/2014/04/28/uniform-random-float
112        // https://mumble.net/~campbell/2014/04/28/random_real.c
113        // https://github.com/Lokathor/randomize/issues/34
114        const TOTAL_BITS: u32 = 32;
115        const PRECISION: u32 = core::f32::MANTISSA_DIGITS;
116        const MANTISSA_SCALE: f32 = 1.0 / ((1u32 << PRECISION) as f32);
117        let mut u = self.rand_u32();
118        u >>= TOTAL_BITS - PRECISION;
119        u as f32 * MANTISSA_SCALE
120    }
121
122    /// Produces a random within the given bounds.  Like any `Range`,
123    /// it includes the lower bound and excludes the upper one.
124    ///
125    /// This should be faster than `Self::rand() % end + start`, but the
126    /// real advantage is it's more convenient.  Requires that
127    /// `range.end <= range.start`.
128    pub fn rand_range(&mut self, range: Range<u32>) -> u32 {
129        // This is harder to do well than it looks, it seems.  I don't
130        // trust Lokathor's implementation 'cause I don't understand
131        // it, so I went to numpy's, which points me to "Lemire's
132        // rejection algorithm": http://arxiv.org/abs/1805.10941
133        //
134        // Algorithms 3, 4 and 5 in that paper all seem fine modulo
135        // minor performance differences, so this is algorithm 5.
136        // It uses numpy's implementation, `buffered_bounded_lemire_uint32()`
137
138        debug_assert!(range.start < range.end);
139        let range_starting_from_zero = 0..(range.end - range.start);
140
141        let s: u32 = range_starting_from_zero.end;
142        let mut m: u64 = u64::from(self.rand_u32()) * u64::from(s);
143        let mut leftover: u32 = (m & 0xFFFF_FFFF) as u32;
144
145        if leftover < s {
146            // TODO: verify the wrapping_neg() here
147            let threshold: u32 = s.wrapping_neg() % s;
148            while leftover < threshold {
149                m = u64::from(self.rand_u32()).wrapping_mul(u64::from(s));
150                leftover = (m & 0xFFFF_FFFF) as u32;
151            }
152        }
153        (m >> 32) as u32 + range.start
154    }
155}
156
157/// A PRNG producing a 64-bit output.
158///
159/// The current implementation is `PCG-XSH-RR`.
160// BUGGO: The recommended algorithm is PCG-XSL-RR?
161// See https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L2405
162// Not sure if it matters?
163#[derive(Copy, Clone, Debug, PartialEq, Eq)]
164pub struct Rand64 {
165    state: u128,
166    inc: u128,
167}
168
169impl Rand64 {
170    /// The default value for `increment`.
171    ///
172    /// The value used here is from the PCG default C implementation: http://www.pcg-random.org/download.html
173    pub const DEFAULT_INC: u128 = 0x2FE0E169_FFBD06E3_5BC307BD_4D2F814F;
174
175    /// This is the number that you have to Really Get Right.
176    ///
177    /// The value used here is from the PCG C implementation:
178    /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L288
179    pub(crate) const MULTIPLIER: u128 = 47026247687942121848144207491837523525;
180
181    /// Creates a new PRNG with the given seed and a default increment.
182    pub fn new(seed: u128) -> Self {
183        Self::new_inc(seed, Self::DEFAULT_INC)
184    }
185
186    /// Same as `Rand32::new_inc()`
187    pub fn new_inc(seed: u128, increment: u128) -> Self {
188        let mut rng = Self {
189            state: 0,
190            inc: increment.wrapping_shl(1) | 1,
191        };
192        let _ = rng.rand_u64();
193        rng.state = rng.state.wrapping_add(seed);
194        let _ = rng.rand_u64();
195        rng
196    }
197
198    /// Returns the internal state of the PRNG.  This allows
199    /// you to save a PRNG and create a new one that will resume
200    /// from the same spot in the sequence.
201    pub fn state(&self) -> (u128, u128) {
202        (self.state, self.inc)
203    }
204
205    /// Creates a new PRNG from a saved state from `Rand32::state()`.
206    /// This is NOT quite the same as `new_inc()` because `new_inc()` does
207    /// a little extra setup work to initialize the state.
208    pub fn from_state(state: (u128, u128)) -> Self {
209        let (state, inc) = state;
210        Self { state, inc }
211    }
212
213    /// Produces a random `u64` in the range`[0, u64::MAX]`.
214    pub fn rand_u64(&mut self) -> u64 {
215        let oldstate: u128 = self.state;
216        self.state = oldstate
217            .wrapping_mul(Self::MULTIPLIER)
218            .wrapping_add(self.inc);
219        let xorshifted: u64 = (((oldstate >> 29) ^ oldstate) >> 58) as u64;
220        let rot: u32 = (oldstate >> 122) as u32;
221        xorshifted.rotate_right(rot)
222    }
223
224    /// Produces a random `i64` in the range `[i64::MIN, i64::MAX]`.
225    pub fn rand_i64(&mut self) -> i64 {
226        self.rand_u64() as i64
227    }
228
229    /// Produces a random `f64` in the range `[0.0, 1.0)`.
230    pub fn rand_float(&mut self) -> f64 {
231        const TOTAL_BITS: u32 = 64;
232        const PRECISION: u32 = core::f64::MANTISSA_DIGITS;
233        const MANTISSA_SCALE: f64 = 1.0 / ((1u64 << PRECISION) as f64);
234        let mut u = self.rand_u64();
235        u >>= TOTAL_BITS - PRECISION;
236        u as f64 * MANTISSA_SCALE
237    }
238
239    /// Produces a random within the given bounds.  Like any `Range`,
240    /// it includes the lower bound and excludes the upper one.
241    ///
242    /// This should be faster than `Self::rand() % end + start`, but the
243    /// real advantage is it's more convenient.  Requires that
244    /// `range.end <= range.start`.
245    pub fn rand_range(&mut self, range: Range<u64>) -> u64 {
246        // Same as `Rand32::rand_range()`
247        debug_assert!(range.start < range.end);
248        let range_starting_from_zero = 0..(range.end - range.start);
249
250        let s: u64 = range_starting_from_zero.end;
251        let mut m: u128 = u128::from(self.rand_u64()) * u128::from(s);
252        let mut leftover: u64 = (m & 0xFFFFFFFF_FFFFFFFF) as u64;
253
254        if leftover < s {
255            // TODO: Verify the wrapping_negate() here
256            let threshold: u64 = s.wrapping_neg() % s;
257            while leftover < threshold {
258                m = u128::from(self.rand_u64()) * u128::from(s);
259                leftover = (m & 0xFFFFFFFF_FFFFFFFF) as u64;
260            }
261        }
262        (m.wrapping_shr(64)) as u64 + range.start
263    }
264}
265
266#[cfg(test)]
267mod tests {
268    use super::*;
269    use randomize::{self, PCG32, PCG64};
270
271    #[test]
272    fn test_rand32_vs_randomize() {
273        // Generate some random numbers and validate them against
274        // a known-good generator.
275        {
276            let seed = 54321;
277            let mut r1 = Rand32::new(seed);
278            let mut r2 = PCG32::seed(seed, Rand32::DEFAULT_INC);
279            for _ in 0..1000 {
280                assert_eq!(r1.rand_u32(), r2.next_u32());
281                assert_eq!(r1.rand_i32(), r2.next_u32() as i32);
282            }
283        }
284
285        {
286            let seed = 3141592653;
287            let inc = 0xDEADBEEF;
288            let mut r1 = Rand32::new_inc(seed, inc);
289            let mut r2 = PCG32::seed(seed, inc);
290            for _ in 0..1000 {
291                assert_eq!(r1.rand_u32(), r2.next_u32());
292                assert_eq!(r1.rand_i32(), r2.next_u32() as i32);
293            }
294        }
295    }
296
297    #[test]
298    fn test_rand64_vs_randomize() {
299        // Generate some random numbers and validate them against
300        // a known-good generator.
301        {
302            let seed = 54321;
303            let mut r1 = Rand64::new(seed);
304            let mut r2 = PCG64::seed(seed, Rand64::DEFAULT_INC);
305            for _ in 0..1000 {
306                assert_eq!(r1.rand_u64(), r2.next_u64());
307                assert_eq!(r1.rand_i64(), r2.next_u64() as i64);
308            }
309        }
310
311        {
312            let seed = 3141592653;
313            let inc = 0xDEADBEEF;
314            let mut r1 = Rand64::new_inc(seed, inc);
315            let mut r2 = PCG64::seed(seed, inc);
316            for _ in 0..1000 {
317                assert_eq!(r1.rand_u64(), r2.next_u64());
318                assert_eq!(r1.rand_i64(), r2.next_u64() as i64);
319            }
320        }
321    }
322
323    #[test]
324    fn test_float32() {
325        {
326            let seed = 2718281828;
327            let mut r1 = Rand32::new(seed);
328            let mut r2 = PCG32::seed(seed, Rand32::DEFAULT_INC);
329            for _ in 0..1000 {
330                // First just make sure they both work with randomize's
331                // f32 conversion function -- sanity checks.
332                let i1 = r1.rand_u32();
333                let i2 = r2.next_u32();
334                assert_eq!(i1, i2);
335                let f1 = randomize::f32_half_open_right(i1);
336                let f2 = randomize::f32_half_open_right(i2);
337                // We can directly compare floats 'cause we do no math, it's
338                // literally the same bitwise algorithm with the same inputs.
339                assert_eq!(f1, f2);
340
341                // Make sure result is in [0.0, 1.0)
342                assert!(f1 >= 0.0);
343                assert!(f1 < 1.0);
344            }
345
346            // At least make sure our float's from rand_float() are in the valid range.
347            for _ in 0..1000 {
348                let f1 = r1.rand_float();
349                assert!(f1 >= 0.0);
350                assert!(f1 < 1.0);
351            }
352
353            /*
354            TODO: Randomize changed its int-to-float conversion functions and now they don't
355            match ours.
356            for _ in 0..1000 {
357                // Now make sure our own float conversion function works.
358                let f1 = r1.rand_float();
359                //let f2 = randomize::f32_half_open_right(r2.next_u32());
360                let f2 = randomize::f32_open(r2.next_u32());
361                assert_eq!(f1, f2);
362                assert!(f1 >= 0.0);
363                assert!(f1 < 1.0);
364            }
365            */
366        }
367    }
368
369    #[test]
370    fn test_float64() {
371        {
372            let seed = 2718281828;
373            let mut r1 = Rand64::new(seed);
374            let mut r2 = PCG64::seed(seed, Rand64::DEFAULT_INC);
375            for _ in 0..1000 {
376                // First just make sure they both work with randomize's
377                // f64 conversion function -- sanity checks.
378                let i1 = r1.rand_u64();
379                let i2 = r2.next_u64();
380                assert_eq!(i1, i2);
381                let f1 = randomize::f64_half_open_right(i1);
382                let f2 = randomize::f64_half_open_right(i2);
383                // We can directly compare floats 'cause we do no math, it's
384                // literally the same bitwise algorithm with the same inputs.
385                assert_eq!(f1, f2);
386
387                // Make sure result is in [0.0, 1.0)
388                assert!(f1 >= 0.0);
389                assert!(f1 < 1.0);
390            }
391
392            // At least make sure our float's from rand_float() are in the valid range.
393            for _ in 0..1000 {
394                let f1 = r1.rand_float();
395                assert!(f1 >= 0.0);
396                assert!(f1 < 1.0);
397            }
398
399            /*
400            TODO: Randomize changed its int-to-float conversion functions and now they don't
401            match ours.
402                        for _ in 0..1000 {
403                            // Now make sure our own float conversion function works.
404                            let f1 = r1.rand_float();
405                            //let f2 = randomize::f32_half_open_right(r2.next_u32());
406                            let f2 = randomize::f32_open(r2.next_u32());
407                            assert_eq!(f1, f2);
408                            assert!(f1 >= 0.0);
409                            assert!(f1 < 1.0);
410                        }
411                         */
412        }
413    }
414
415    #[test]
416    fn test_randrange32() {
417        // Make sure ranges are valid and in the given range
418        let seed = 2342_3141;
419        let mut r1 = Rand32::new(seed);
420        for _ in 0..1000 {
421            // Generate our bounds at random
422            let a = r1.rand_u32();
423            let b = r1.rand_u32();
424            if a == b {
425                continue;
426            }
427            let (low, high) = if a < b { (a, b) } else { (b, a) };
428
429            // Get a number in that range
430            let in_range = r1.rand_range(low..high);
431            assert!(in_range >= low);
432            assert!(in_range < high);
433        }
434    }
435
436    #[test]
437    fn test_randrange64() {
438        // Make sure ranges are valid and in the given range
439        let seed = 2342_2718;
440        let mut r1 = Rand64::new(seed);
441        for _ in 0..1000 {
442            // Generate our bounds at random
443            let a = r1.rand_u64();
444            let b = r1.rand_u64();
445            if a == b {
446                continue;
447            }
448            let (low, high) = if a < b { (a, b) } else { (b, a) };
449
450            // Get a number in that range
451            let in_range = r1.rand_range(low..high);
452            assert!(in_range >= low);
453            assert!(in_range < high);
454        }
455    }
456
457    #[test]
458    fn test_rand32_vs_rand() {
459        use rand_core::RngCore;
460        use rand_pcg;
461        {
462            let seed = 54321;
463            let mut r1 = Rand32::new(seed);
464            let mut r2 = rand_pcg::Pcg32::new(seed, Rand32::DEFAULT_INC);
465            for _ in 0..1000 {
466                assert_eq!(r1.rand_u32(), r2.next_u32());
467            }
468        }
469
470        {
471            let seed = 3141592653;
472            let inc = 0xDEADBEEF;
473            let mut r1 = Rand32::new_inc(seed, inc);
474            let mut r2 = rand_pcg::Pcg32::new(seed, inc);
475            for _ in 0..1000 {
476                assert_eq!(r1.rand_u32(), r2.next_u32());
477            }
478        }
479    }
480
481    // This doesn't work 'cause for 64-bit output `rand` uses
482    // PCG-XSL-RR
483    // and we use
484    // PCG-XSH-RR
485    /*
486        #[test]
487        fn test_rand64_vs_rand() {
488            use rand_pcg;
489            use rand_core::RngCore;
490            {
491                let seed = 54321;
492                let mut r1 = Rand64::new(seed);
493                let mut r2 = rand_pcg::Pcg64::new(seed, Rand64::DEFAULT_INC);
494                for _ in 0..1000 {
495                    assert_eq!(r1.rand(), r2.next_u64());
496                }
497            }
498
499            {
500                let seed = 3141592653;
501                let inc = 0xDEADBEEF;
502                let mut r1 = Rand64::new_inc(seed, inc);
503                let mut r2 = rand_pcg::Pcg64::new(seed, inc);
504                for _ in 0..1000 {
505                    assert_eq!(r1.rand(), r2.next_u64());
506                }
507            }
508        }
509    */
510
511    // Test vs. random-fast-rng, which I will call rfr
512    // rfr's float conversion uses yet a different algorithm
513    // than ours, so we can't really check that.
514    #[test]
515    fn test_rand32_vs_rfr() {
516        use random_fast_rng as rfr;
517        use rfr::Random;
518        {
519            let seed = 54321;
520            let mut r1 = Rand32::new(seed);
521            let mut r2 = rfr::FastRng::seed(seed, Rand32::DEFAULT_INC);
522            for _ in 0..1000 {
523                assert_eq!(r1.rand_u32(), r2.get_u32());
524            }
525        }
526
527        {
528            let seed = 3141592653;
529            let inc = 0xDEADBEEF;
530            let mut r1 = Rand32::new_inc(seed, inc);
531            let mut r2 = rfr::FastRng::seed(seed, inc);
532            for _ in 0..1000 {
533                assert_eq!(r1.rand_u32(), r2.get_u32());
534            }
535        }
536    }
537
538    /// Make sure that saving a RNG state and restoring
539    /// it works.
540    /// See https://todo.sr.ht/~icefox/oorandom/1
541    #[test]
542    fn test_save_restore() {
543        {
544            let seed = 54321;
545            let mut r1 = Rand32::new(seed);
546            let s1 = r1.state();
547            let mut r2 = Rand32::from_state(s1);
548            assert_eq!(r1, r2);
549            for _ in 0..1000 {
550                assert_eq!(r1.rand_u32(), r2.rand_u32());
551            }
552        }
553
554        {
555            let seed = 3141592653;
556            let inc = 0xDEADBEEF;
557            let mut r1 = Rand32::new_inc(seed, inc);
558            let s1 = r1.state();
559            let mut r2 = Rand32::from_state(s1);
560            assert_eq!(r1, r2);
561            for _ in 0..1000 {
562                assert_eq!(r1.rand_u32(), r2.rand_u32());
563            }
564        }
565
566        {
567            let seed = 54321;
568            let mut r1 = Rand64::new(seed);
569            let s1 = r1.state();
570            let mut r2 = Rand64::from_state(s1);
571            assert_eq!(r1, r2);
572            for _ in 0..1000 {
573                assert_eq!(r1.rand_u64(), r2.rand_u64());
574            }
575        }
576
577        {
578            let seed = 3141592653;
579            let inc = 0xDEADBEEF;
580            let mut r1 = Rand64::new_inc(seed, inc);
581            let s1 = r1.state();
582            let mut r2 = Rand64::from_state(s1);
583            assert_eq!(r1, r2);
584            for _ in 0..1000 {
585                assert_eq!(r1.rand_u64(), r2.rand_u64());
586            }
587        }
588    }
589}