dandelion/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3
4#[cfg(feature = "std")]
5extern crate std;
6
7use core::num::NonZeroU128;
8
9/// A high performance non-cryptographic random number generator.
10
11#[derive(Clone)]
12pub struct Rng { state: NonZeroU128 }
13
14#[inline(always)]
15const fn get_chunk<T, const N: usize>(slice: &[T], offset: usize) -> &[T; N] {
16  assert!(offset <= slice.len() && N <= slice.len() - offset);
17  unsafe { &*(slice.as_ptr().add(offset) as *const [T; N]) }
18}
19
20#[inline(always)]
21fn get_chunk_mut<T, const N: usize>(slice: &mut [T], offset: usize) -> &mut [T; N] {
22  assert!(offset <= slice.len() && N <= slice.len() - offset);
23  unsafe { &mut *(slice.as_mut_ptr().add(offset) as *mut [T; N]) }
24}
25
26#[inline(always)]
27const fn front_chunk<T, const N: usize>(slice: &[T]) -> &[T; N] {
28  get_chunk(slice, 0)
29}
30
31#[inline(always)]
32fn front_chunk_mut<T, const N: usize>(slice: &mut [T]) -> &mut [T; N] {
33  get_chunk_mut(slice, 0)
34}
35
36#[inline(always)]
37const fn hash(x: NonZeroU128) -> NonZeroU128 {
38  // The hash uses the multiplier
39  //
40  //   M = round_nearest_odd(EULER_MASCHERONI * 2¹²⁸)
41  //
42  // The Euler-Mascheroni constant was selected because it is a well-known
43  // number in the range (0.5, 1.0).
44
45  const M: u128 = 0x93c4_67e3_7db0_c7a4_d1be_3f81_0152_cb57;
46
47  let x = x.get();
48  let x = x.wrapping_mul(M);
49  let x = x.swap_bytes();
50  let x = x.wrapping_mul(M);
51  let x = x.swap_bytes();
52  let x = x.wrapping_mul(M);
53  unsafe { NonZeroU128::new_unchecked(x) }
54}
55
56impl Rng {
57  /// Creates a random number generator with an initial state derived by
58  /// hashing the given byte array.
59
60  pub const fn new(seed: [u8; 15]) -> Self {
61    let x = u64::from_le_bytes(*get_chunk(&seed, 0));
62    let y = u64::from_le_bytes(*get_chunk(&seed, 7));
63    let s = x as u128 | ((y >> 8) as u128) << 64;
64    let s = s | 1 << 120;
65    let s = NonZeroU128::new(s).unwrap();
66    Self { state: hash(s) }
67  }
68
69  /// Creates a random number generator with an initial state derived by
70  /// hashing the given `u64` seed.
71
72  pub const fn from_u64(seed: u64) -> Self {
73    let s = seed as u128;
74    let s = s | 1 << 64;
75    let s = NonZeroU128::new(s).unwrap();
76    Self { state: hash(s) }
77  }
78
79  /// Retrieves the current state of the random number generator.
80
81  #[inline(always)]
82  pub const fn state(&self) -> NonZeroU128 {
83    self.state
84  }
85
86  /// Creates a random number generator with a particular initial state.
87  ///
88  /// <div class="warning">
89  ///
90  /// If you want to deterministically initialize a generator from a small
91  /// integer or other weak seed, you should *NOT* use this function and should
92  /// instead use [Rng::new] or [Rng::from_u64] which hash their arguments.
93  ///
94  /// </div>
95
96  #[inline(always)]
97  pub const fn from_state(state: NonZeroU128) -> Self {
98    Self { state }
99  }
100
101  /// Creates a random number generator with a random seed retrieved from the
102  /// operating system.
103
104  #[cfg(feature = "getrandom")]
105  #[inline(never)]
106  #[cold]
107  pub fn from_operating_system() -> Self {
108    let mut buf = [0; 16];
109    getrandom::fill(&mut buf).expect("getrandom::fill failed!");
110    let s = u128::from_le_bytes(buf);
111    let s = s | 1;
112    let s = NonZeroU128::new(s).unwrap();
113    Self { state: s }
114  }
115
116  /// Splits off a new random number generator that may be used along with the
117  /// original.
118
119  #[inline(always)]
120  pub fn split(&mut self) -> Self {
121    let x = self.u64();
122    let y = self.u64();
123    let s = x as u128 ^ (y as u128) << 64;
124    let s = s | 1;
125    let s = NonZeroU128::new(s).unwrap();
126    Self { state: s }
127  }
128
129  /// Samples a `bool` from the Bernoulli distribution where `true` appears
130  /// with probability approximately equal to `p`.
131  ///
132  /// Probabilities `p` <= 0 or NaN are treated as 0, and `p` >= 1 are
133  /// treated as 1.
134
135  #[inline(always)]
136  pub fn bernoulli(&mut self, p: f64) -> bool {
137    // For every `p` that is representable as a `f64`, is in the range [0, 1],
138    // and is an exact multiple of 2⁻¹²⁸, this procedure samples exactly from
139    // the corresponding Bernoulli distribution, given the (false!) assumption
140    // that `dandelion::u64` samples exactly uniformly.
141    //
142    // In particular `bernoulli(0)` is always `false` and `bernoulli(1)` is
143    // always `true`.
144
145    let x = self.u64();
146    let e = 1022 - x.trailing_zeros() as u64;
147    let t = f64::from_bits((e << 52) + (x >> 12));
148    t < p
149  }
150
151  /// Samples a `bool` from the uniform distribution.
152
153  #[inline(always)]
154  pub fn bool(&mut self) -> bool {
155    self.i64() < 0
156  }
157
158  /// Samples a `i32` from the uniform distribution.
159
160  #[inline(always)]
161  pub fn i32(&mut self) -> i32 {
162    self.u64() as i32
163  }
164
165  /// Samples a `i64` from the uniform distribution.
166
167  #[inline(always)]
168  pub fn i64(&mut self) -> i64 {
169    self.u64() as i64
170  }
171
172  /// Samples a `u32` from the uniform distribution.
173
174  #[inline(always)]
175  pub fn u32(&mut self) -> u32 {
176    self.u64() as u32
177  }
178
179  /// Samples a `u64` from the uniform distribution.
180
181  #[inline(always)]
182  pub fn u64(&mut self) -> u64 {
183    let s = self.state.get();
184    let x = s as u64;
185    let y = (s >> 64) as u64;
186    let u = y ^ y >> 19;
187    let v = x ^ y.rotate_right(7);
188    let w = x as u128 * x as u128;
189    let z = y.wrapping_add(w as u64 ^ (w >> 64) as u64);
190    let s = u as u128 ^ (v as u128) << 64;
191    self.state = unsafe { NonZeroU128::new_unchecked(s) };
192    z
193  }
194
195  /// Samples a `u32` from the uniform distribution over the range `0 ... n`.
196  ///
197  /// The upper bound is inclusive.
198
199  #[inline(always)]
200  pub fn bounded_u32(&mut self, n: u32) -> u32 {
201    // Cf. `bounded_u64`.
202
203    let x = self.u64() as u128;
204    let y = self.u64() as u128;
205    let n = n as u128;
206    let u = x * n + x >> 64;
207    let v = y * n + y;
208    let z = u + v >> 64;
209    z as u32
210  }
211
212  /// Samples a `u64` from the uniform distribution over the range `0 ... n`.
213  ///
214  /// The upper bound is inclusive.
215
216  #[inline(always)]
217  pub fn bounded_u64(&mut self, n: u64) -> u64 {
218    // This procedure computes
219    //
220    //   floor((k * n + k) / 2¹²⁸)
221    //
222    // where k is sampled approximately uniformly from 0 ... 2¹²⁸ - 1.  The
223    // result is a very low bias sample from the desired distribution.
224
225    //     y x                  x        y 0      v v 0
226    // *     n            *     n    *     n    +   u _
227    // +   y x  ------->  +     x    +   y 0
228    // -------            -------    -------    -------
229    //   z _ _                u _      v v 0      z _ _
230
231    let x = self.u64() as u128;
232    let y = self.u64() as u128;
233    let n = n as u128;
234    let u = x * n + x >> 64;
235    let v = y * n + y;
236    let z = u + v >> 64;
237    z as u64
238  }
239
240  /// Samples a `i32` from the uniform distribution over the range `lo ... hi`.
241  ///
242  /// The lower and upper bounds are inclusive, and the range can wrap around
243  /// from `i32::MAX` to `i32::MIN`.
244
245  #[inline(always)]
246  pub fn between_i32(&mut self, lo: i32, hi: i32) -> i32 {
247    self.between_u32(lo as u32, hi as u32) as i32
248  }
249
250  /// Samples a `i64` from the uniform distribution over the range `lo ... hi`.
251  ///
252  /// The lower and upper bounds are inclusive, and the range can wrap around
253  /// from `i64::MAX` to `i64::MIN`.
254
255  #[inline(always)]
256  pub fn between_i64(&mut self, lo: i64, hi: i64) -> i64 {
257    self.between_u64(lo as u64, hi as u64) as i64
258  }
259
260  /// Samples a `u32` from the uniform distribution over the range `lo ... hi`.
261  ///
262  /// The lower and upper bounds are inclusive, and the range can wrap around
263  /// from `u32::MAX` to `u32::MIN`.
264
265  #[inline(always)]
266  pub fn between_u32(&mut self, lo: u32, hi: u32) -> u32 {
267    lo.wrapping_add(self.bounded_u32(hi.wrapping_sub(lo)))
268  }
269
270  /// Samples a `u64` from the uniform distribution over the range `lo ... hi`.
271  ///
272  /// The lower and upper bounds are inclusive, and the range can wrap around
273  /// from `u64::MAX` to `u64::MIN`.
274
275  #[inline(always)]
276  pub fn between_u64(&mut self, lo: u64, hi: u64) -> u64 {
277    lo.wrapping_add(self.bounded_u64(hi.wrapping_sub(lo)))
278  }
279
280  /// Samples a `f32` from a distribution that approximates the uniform
281  /// distribution over the real interval [0, 1].
282  ///
283  /// The distribution is the same as the one produced by the following
284  /// procedure:
285  ///
286  /// - Sample a real number from the uniform distribution on [0, 1].
287  /// - Round to the nearest multiple of 2⁻⁶³.
288  /// - Round to a `f32` using the default rounding mode.
289  ///
290  /// A zero output will always be +0, never -0.
291
292  #[inline(always)]
293  pub fn f32(&mut self) -> f32 {
294    let x = self.i64();
295    let x = f32::from_bits(0x2000_0000) * x as f32;
296    f32::from_bits(0x7fff_ffff & x.to_bits())
297  }
298
299  /// Samples a `f64` from a distribution that approximates the uniform
300  /// distribution over the real interval [0, 1].
301  ///
302  /// The distribution is the same as the one produced by the following
303  /// procedure:
304  ///
305  /// - Sample a real number from the uniform distribution on [0, 1].
306  /// - Round to the nearest multiple of 2⁻⁶³.
307  /// - Round to a `f64` using the default rounding mode.
308  ///
309  /// A zero output will always be +0, never -0.
310
311  #[inline(always)]
312  pub fn f64(&mut self) -> f64 {
313    // The conversion into a `f64` is two instructions on aarch64:
314    //
315    //   scvtf d0, x8, #63
316    //   fabs d0, d0
317
318    let x = self.i64();
319    let x = f64::from_bits(0x3c00_0000_0000_0000) * x as f64;
320    f64::from_bits(0x7fff_ffff_ffff_ffff & x.to_bits())
321  }
322
323  #[inline(always)]
324  fn bytes_inlined(&mut self, dst: &mut [u8]) {
325    let mut dst = dst;
326
327    if dst.len() == 0 {
328      return;
329    }
330
331    while dst.len() >= 17 {
332      let x = self.u64();
333      let y = self.u64();
334      *front_chunk_mut(dst) = x.to_le_bytes();
335      dst = &mut dst[8 ..];
336      *front_chunk_mut(dst) = y.to_le_bytes();
337      dst = &mut dst[8 ..];
338    }
339
340    if dst.len() >= 9 {
341      let x = self.u64();
342      *front_chunk_mut(dst) = x.to_le_bytes();
343      dst = &mut dst[8 ..];
344    }
345
346    let x = self.u64();
347
348    match dst.len() {
349      1 => *front_chunk_mut(dst) = *front_chunk::<u8, 1>(&x.to_le_bytes()),
350      2 => *front_chunk_mut(dst) = *front_chunk::<u8, 2>(&x.to_le_bytes()),
351      3 => *front_chunk_mut(dst) = *front_chunk::<u8, 3>(&x.to_le_bytes()),
352      4 => *front_chunk_mut(dst) = *front_chunk::<u8, 4>(&x.to_le_bytes()),
353      5 => *front_chunk_mut(dst) = *front_chunk::<u8, 5>(&x.to_le_bytes()),
354      6 => *front_chunk_mut(dst) = *front_chunk::<u8, 6>(&x.to_le_bytes()),
355      7 => *front_chunk_mut(dst) = *front_chunk::<u8, 7>(&x.to_le_bytes()),
356      8 => *front_chunk_mut(dst) = *front_chunk::<u8, 8>(&x.to_le_bytes()),
357      _ => unreachable!(),
358    }
359  }
360
361  /// Fills the provided buffer with independent uniformly distributed bytes.
362
363  pub fn bytes(&mut self, dst: &mut [u8]) {
364    self.bytes_inlined(dst);
365  }
366
367  /// Samples an array of independent uniformly distributed bytes.
368
369  pub fn byte_array<const N: usize>(&mut self) -> [u8; N] {
370    let mut buf = [0; N];
371    self.bytes_inlined(&mut buf);
372    buf
373  }
374}
375
376#[cfg(feature = "rand_core")]
377impl rand_core::RngCore for Rng {
378  #[inline(always)]
379  fn next_u32(&mut self) -> u32 {
380    self.u32()
381  }
382
383  #[inline(always)]
384  fn next_u64(&mut self) -> u64 {
385    self.u64()
386  }
387
388  fn fill_bytes(&mut self, dst: &mut [u8]) {
389    self.bytes(dst)
390  }
391}
392
393#[cfg(feature = "rand_core")]
394impl rand_core::SeedableRng for Rng {
395  type Seed = [u8; 16];
396
397  fn from_seed(seed: Self::Seed) -> Self {
398    let s = u128::from_le_bytes(seed);
399    let s = s | 1;
400    let s = NonZeroU128::new(s).unwrap();
401    Self::from_state(s)
402  }
403
404  fn seed_from_u64(seed: u64) -> Self {
405    Self::from_u64(seed)
406  }
407
408  fn from_rng(rng: &mut impl rand_core::RngCore) -> Self {
409    let x = rng.next_u64();
410    let y = rng.next_u64();
411    let s = x as u128 ^ (y as u128) << 64;
412    let s = s | 1;
413    let s = NonZeroU128::new(s).unwrap();
414    Self::from_state(s)
415  }
416}
417
418#[cfg(feature = "thread_local")]
419pub mod thread_local {
420  //! Access a thread-local random number generator.
421  //!
422  //! If you want to generate many random numbers, you should create a local
423  //! generator with [dandelion::thread_local::split](split).
424
425  use core::cell::Cell;
426  use core::num::NonZeroU128;
427
428  use crate::Rng;
429
430  std::thread_local! {
431    static RNG: Cell<Option<NonZeroU128>> = const {
432      Cell::new(None)
433    };
434  }
435
436  // The function `with` is *NOT* logically re-entrant, so we must not expose
437  // it publicly.
438
439  #[inline(always)]
440  fn with<F, T>(f: F) -> T
441  where
442    F: FnOnce(&mut Rng) -> T
443  {
444    RNG.with(|cell| {
445      let mut rng =
446        match cell.get() {
447          None =>
448            Rng::from_operating_system(),
449          Some(s) =>
450            Rng::from_state(s),
451        };
452      let x = f(&mut rng);
453      cell.set(Some(rng.state()));
454      x
455    })
456  }
457
458  /// See [Rng::split].
459
460  pub fn split() -> Rng {
461    with(|rng| rng.split())
462  }
463
464  /// See [Rng::bernoulli].
465
466  pub fn bernoulli(p: f64) -> bool {
467    with(|rng| rng.bernoulli(p))
468  }
469
470  /// See [Rng::bool].
471
472  pub fn bool() -> bool {
473    with(|rng| rng.bool())
474  }
475
476  /// See [Rng::i32].
477
478  pub fn i32() -> i32 {
479    with(|rng| rng.i32())
480  }
481
482  /// See [Rng::i64].
483
484  pub fn i64() -> i64 {
485    with(|rng| rng.i64())
486  }
487
488  /// See [Rng::u32].
489
490  pub fn u32() -> u32 {
491    with(|rng| rng.u32())
492  }
493
494  /// See [Rng::u64].
495
496  pub fn u64() -> u64 {
497    with(|rng| rng.u64())
498  }
499
500  /// See [Rng::bounded_u32].
501
502  pub fn bounded_u32(n: u32) -> u32 {
503    with(|rng| rng.bounded_u32(n))
504  }
505
506  /// See [Rng::bounded_u64].
507
508  pub fn bounded_u64(n: u64) -> u64 {
509    with(|rng| rng.bounded_u64(n))
510  }
511
512  /// See [Rng::between_i32].
513
514  pub fn between_i32(lo: i32, hi: i32) -> i32 {
515    with(|rng| rng.between_i32(lo, hi))
516  }
517
518  /// See [Rng::between_i64].
519
520  pub fn between_i64(lo: i64, hi: i64) -> i64 {
521    with(|rng| rng.between_i64(lo, hi))
522  }
523
524  /// See [Rng::between_u32].
525
526  pub fn between_u32(lo: u32, hi: u32) -> u32 {
527    with(|rng| rng.between_u32(lo, hi))
528  }
529
530  /// See [Rng::between_u64].
531
532  pub fn between_u64(lo: u64, hi: u64) -> u64 {
533    with(|rng| rng.between_u64(lo, hi))
534  }
535
536  /// See [Rng::f32].
537
538  pub fn f32() -> f32 {
539    with(|rng| rng.f32())
540  }
541
542  /// See [Rng::f64].
543
544  pub fn f64() -> f64 {
545    with(|rng| rng.f64())
546  }
547
548  /// See [Rng::bytes].
549
550  pub fn bytes(dst: &mut [u8]) {
551    with(|rng| rng.bytes(dst))
552  }
553
554  /// See [Rng::byte_array].
555
556  pub fn byte_array<const N: usize>() -> [u8; N] {
557    with(|rng| rng.byte_array())
558  }
559}