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.

76 lines
1.8KB

  1. #include "random.hpp"
  2. #include "math.hpp"
  3. #include <time.h>
  4. #include <sys/time.h>
  5. namespace rack {
  6. namespace random {
  7. // xoroshiro128+
  8. // from http://xoroshiro.di.unimi.it/xoroshiro128plus.c
  9. static uint64_t xoroshiro128plus_state[2] = {};
  10. static uint64_t rotl(const uint64_t x, int k) {
  11. return (x << k) | (x >> (64 - k));
  12. }
  13. static uint64_t xoroshiro128plus_next(void) {
  14. const uint64_t s0 = xoroshiro128plus_state[0];
  15. uint64_t s1 = xoroshiro128plus_state[1];
  16. const uint64_t result = s0 + s1;
  17. s1 ^= s0;
  18. xoroshiro128plus_state[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
  19. xoroshiro128plus_state[1] = rotl(s1, 36); // c
  20. return result;
  21. }
  22. void init() {
  23. // Only allow the seed to be initialized once during the lifetime of the program.
  24. assert(xoroshiro128plus_state[0] == 0 && xoroshiro128plus_state[1] == 0);
  25. struct timeval tv;
  26. gettimeofday(&tv, NULL);
  27. xoroshiro128plus_state[0] = tv.tv_sec;
  28. xoroshiro128plus_state[1] = tv.tv_usec;
  29. // Generate a few times to fix the fact that the time is not a uniform u64
  30. for (int i = 0; i < 10; i++) {
  31. xoroshiro128plus_next();
  32. }
  33. }
  34. uint32_t u32() {
  35. return xoroshiro128plus_next() >> 32;
  36. }
  37. uint64_t u64() {
  38. return xoroshiro128plus_next();
  39. }
  40. float uniform() {
  41. // 24 bits of granularity is the best that can be done with floats while ensuring that the return value lies in [0.0, 1.0).
  42. return (xoroshiro128plus_next() >> (64 - 24)) / std::pow(2, 24);
  43. }
  44. float normal() {
  45. // Box-Muller transform
  46. float radius = std::sqrt(-2.f * std::log(1.f - uniform()));
  47. float theta = 2.f * M_PI * uniform();
  48. return radius * std::sin(theta);
  49. // // Central Limit Theorem
  50. // const int n = 8;
  51. // float sum = 0.0;
  52. // for (int i = 0; i < n; i++) {
  53. // sum += uniform();
  54. // }
  55. // return (sum - n / 2.f) / std::sqrt(n / 12.f);
  56. }
  57. } // namespace random
  58. } // namespace rack