random.h (2020B)
1 // This file is part of AsmJit project <https://asmjit.com> 2 // 3 // See <asmjit/core.h> or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #ifndef TESTING_COMMONS_RANDOM_H_INCLUDED 7 #define TESTING_COMMONS_RANDOM_H_INCLUDED 8 9 #include <stdint.h> 10 #include <string.h> 11 12 namespace TestUtils { 13 namespace { 14 15 // A pseudo random number generator based on a paper by Sebastiano Vigna: 16 // http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf 17 class Random { 18 public: 19 // Constants suggested as `23/18/5`. 20 static inline constexpr uint32_t kStep1_SHL = 23; 21 static inline constexpr uint32_t kStep2_SHR = 18; 22 static inline constexpr uint32_t kStep3_SHR = 5; 23 24 uint64_t _state[2]; 25 26 inline explicit Random(uint64_t seed = 0) noexcept { reset(seed); } 27 inline Random(const Random& other) noexcept = default; 28 29 inline void reset(uint64_t seed = 0) noexcept { 30 // The number is arbitrary, it means nothing. 31 constexpr uint64_t kZeroSeed = 0x1F0A2BE71D163FA0u; 32 33 // Generate the state data by using splitmix64. 34 for (uint32_t i = 0; i < 2; i++) { 35 seed += 0x9E3779B97F4A7C15u; 36 uint64_t x = seed; 37 x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9u; 38 x = (x ^ (x >> 27)) * 0x94D049BB133111EBu; 39 x = (x ^ (x >> 31)); 40 _state[i] = x != 0 ? x : kZeroSeed; 41 } 42 } 43 44 inline uint32_t next_uint32() noexcept { 45 return uint32_t(next_uint64() >> 32); 46 } 47 48 inline uint64_t next_uint64() noexcept { 49 uint64_t x = _state[0]; 50 uint64_t y = _state[1]; 51 52 x ^= x << kStep1_SHL; 53 y ^= y >> kStep3_SHR; 54 x ^= x >> kStep2_SHR; 55 x ^= y; 56 57 _state[0] = y; 58 _state[1] = x; 59 return x + y; 60 } 61 62 inline double next_double() noexcept { 63 constexpr uint32_t kMantissaShift = 64 - 52; 64 constexpr uint64_t kExpMsk = 0x3FF0000000000000u; 65 66 uint64_t u = (next_uint64() >> kMantissaShift) | kExpMsk; 67 double d = 0.0; 68 69 memcpy(&d, &u, 8); 70 return d - 1.0; 71 } 72 }; 73 74 } // {anonymous} 75 } // {TestUtils} 76 77 #endif // TESTING_COMMONS_RANDOM_H_INCLUDED