You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
2.5KB

  1. #pragma once
  2. #include <common.hpp>
  3. #include <random>
  4. #include <vector>
  5. namespace rack {
  6. /** Random number generation
  7. */
  8. namespace random {
  9. /** xoroshiro128+. Very fast, not-cryptographic random number generator.
  10. From https://prng.di.unimi.it/
  11. Example:
  12. std::random_device rd;
  13. random::Xoroshiro128Plus rng(rd(), rd());
  14. uint64_t r = rng();
  15. uint32_t r = rng.u32();
  16. std::uniform_real_distribution<float> uniform(0.f, 1.f);
  17. float r = uniform(rng);
  18. std::normal_distribution<> normal(0.0, 1.0);
  19. double r = normal(rng);
  20. */
  21. struct Xoroshiro128Plus {
  22. uint64_t state[2] = {};
  23. void seed(uint64_t s0, uint64_t s1) {
  24. state[0] = s0;
  25. state[1] = s1;
  26. // A bad seed will give a bad first result, so shift the state
  27. operator()();
  28. }
  29. bool isSeeded() {
  30. return state[0] || state[1];
  31. }
  32. static uint64_t rotl(uint64_t x, int k) {
  33. return (x << k) | (x >> (64 - k));
  34. }
  35. uint64_t operator()() {
  36. uint64_t s0 = state[0];
  37. uint64_t s1 = state[1];
  38. uint64_t result = s0 + s1;
  39. s1 ^= s0;
  40. state[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14);
  41. state[1] = rotl(s1, 36);
  42. return result;
  43. }
  44. constexpr uint64_t min() const {
  45. return 0;
  46. }
  47. constexpr uint64_t max() const {
  48. return UINT64_MAX;
  49. }
  50. uint64_t u64() {
  51. return operator()();
  52. }
  53. uint64_t u32() {
  54. // Take top 32 bits which has better randomness properties.
  55. return u64() >> 32;
  56. }
  57. uint16_t u16() {
  58. return u64() >> 48;
  59. }
  60. uint8_t u8() {
  61. return u64() >> 56;
  62. }
  63. float f32() {
  64. // The multiplier is 2f7fffff in hex. This gives maximum precision of uint32_t -> float conversion and its image is [0, 1).
  65. return u32() * 2.32830629e-10f;
  66. }
  67. float f64() {
  68. return u64() * 5.421010862427522e-20;
  69. }
  70. };
  71. // Simple random API
  72. /** Initializes the thread-local RNG state.
  73. Must call when creating a thread, otherwise random state is undefined (might always return 0).
  74. */
  75. void init();
  76. /** Returns the thread-local generator.
  77. */
  78. Xoroshiro128Plus& get();
  79. /** Returns a uniform random uint64_t from 0 to UINT64_MAX */
  80. inline uint64_t u64() {
  81. return get().u64();
  82. }
  83. /** Returns a uniform random uint32_t from 0 to UINT32_MAX */
  84. inline uint32_t u32() {
  85. return get().u32();
  86. }
  87. /** Returns a uniform random float in the interval [0.0, 1.0) */
  88. inline float uniform() {
  89. return get().f32();
  90. }
  91. /** Returns a normal random number with mean 0 and standard deviation 1 */
  92. float normal();
  93. /** Fills an array with random bytes. */
  94. void buffer(uint8_t* out, size_t len);
  95. /** Creates a vector of random bytes. */
  96. std::vector<uint8_t> vector(size_t len);
  97. } // namespace random
  98. } // namespace rack