| 58 | } |
| 59 | |
| 60 | inline uint64_t fast_rand_impl(uint64_t range, FastRandSeed* seed) { |
| 61 | // Separating uint64_t values into following intervals: |
| 62 | // [0,range-1][range,range*2-1] ... [uint64_max/range*range,uint64_max] |
| 63 | // If the generated 64-bit random value falls into any interval except the |
| 64 | // last one, the probability of taking any value inside [0, range-1] is |
| 65 | // same. If the value falls into last interval, we retry the process until |
| 66 | // the value falls into other intervals. If min/max are limited to 32-bits, |
| 67 | // the retrying is rare. The amortized retrying count at maximum is 1 when |
| 68 | // range equals 2^32. A corner case is that even if the range is power of |
| 69 | // 2(e.g. min=0 max=65535) in which case the retrying can be avoided, we |
| 70 | // still retry currently. The reason is just to keep the code simpler |
| 71 | // and faster for most cases. |
| 72 | const uint64_t div = std::numeric_limits<uint64_t>::max() / range; |
| 73 | uint64_t result; |
| 74 | do { |
| 75 | result = xorshift128_next(seed) / div; |
| 76 | } while (result >= range); |
| 77 | return result; |
| 78 | } |
| 79 | |
| 80 | // Seeds for different threads are stored separately in thread-local storage. |
| 81 | static __thread FastRandSeed _tls_seed = { { 0, 0 } }; |
no test coverage detected