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.

82 lines
1.8KB

  1. #include <atomic>
  2. #include <time.h>
  3. #include <sys/time.h>
  4. #include <random.hpp>
  5. #include <math.hpp>
  6. namespace rack {
  7. namespace random {
  8. // xoroshiro128+
  9. // from http://xoroshiro.di.unimi.it/xoroshiro128plus.c
  10. thread_local uint64_t xoroshiro128plus_state[2];
  11. static std::atomic<uint64_t> threadCounter {0};
  12. static uint64_t rotl(const uint64_t x, int k) {
  13. return (x << k) | (x >> (64 - k));
  14. }
  15. static uint64_t xoroshiro128plus_next(void) {
  16. const uint64_t s0 = xoroshiro128plus_state[0];
  17. uint64_t s1 = xoroshiro128plus_state[1];
  18. const uint64_t result = s0 + s1;
  19. s1 ^= s0;
  20. xoroshiro128plus_state[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
  21. xoroshiro128plus_state[1] = rotl(s1, 36); // c
  22. return result;
  23. }
  24. void init() {
  25. // Do nothing if already initialized
  26. if (xoroshiro128plus_state[0] || xoroshiro128plus_state[1])
  27. return;
  28. struct timeval tv;
  29. gettimeofday(&tv, NULL);
  30. xoroshiro128plus_state[0] = uint64_t(tv.tv_sec) * 1000000 + tv.tv_usec;
  31. xoroshiro128plus_state[1] = threadCounter++;
  32. // Shift a few times to fix the fact that the seed is not a uniform u64
  33. for (int i = 0; i < 10; i++) {
  34. xoroshiro128plus_next();
  35. }
  36. }
  37. uint32_t u32() {
  38. return xoroshiro128plus_next() >> 32;
  39. }
  40. uint64_t u64() {
  41. return xoroshiro128plus_next();
  42. }
  43. float uniform() {
  44. // The multiplier is 2f7fffff in hex. This gives maximum precision of uint32_t -> float conversion and its image is [0, 1).
  45. return u32() * 2.32830629e-10f;
  46. }
  47. float normal() {
  48. // Box-Muller transform
  49. float radius = std::sqrt(-2.f * std::log(1.f - uniform()));
  50. float theta = 2.f * M_PI * uniform();
  51. return radius * std::sin(theta);
  52. // // Central Limit Theorem
  53. // const int n = 8;
  54. // float sum = 0.0;
  55. // for (int i = 0; i < n; i++) {
  56. // sum += uniform();
  57. // }
  58. // return (sum - n / 2.f) / std::sqrt(n / 12.f);
  59. }
  60. } // namespace random
  61. } // namespace rack