random/stream.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief `RandomStream`, a counter-based random number stream, and 64-bit ID splitting. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/random/philox.h" | ||
| 6 | |||
| 7 | #include <cstdint> | ||
| 8 | |||
| 9 | namespace terraingen { | ||
| 10 | |||
| 11 | /// A counter-based stream of random numbers built on `Philox4x32`. | ||
| 12 | /// | ||
| 13 | /// The key is (`seed`, `stream`); the words `a`, `b` and `c` address an independent substream, so | ||
| 14 | /// the numbers for one cell never depend on any other cell. Each substream gives 2^34 draws before | ||
| 15 | /// it repeats. | ||
| 16 | class RandomStream { | ||
| 17 | public: | ||
| 18 | /// Opens a substream. | ||
| 19 | /// @param stream Separates purposes, such as a layer or a feature kind. | ||
| 20 | /// @param a First substream word, e.g. a cell's x. | ||
| 21 | /// @param b Second substream word, e.g. a cell's y. | ||
| 22 | /// @param c Third substream word, e.g. a size band. | ||
| 23 | RandomStream(std::uint32_t seed, std::uint32_t stream, std::uint32_t a = 0, std::uint32_t b = 0, | ||
| 24 | std::uint32_t c = 0); | ||
| 25 | |||
| 26 | /// The next uniformly distributed 32-bit word. | ||
| 27 | std::uint32_t NextU32(); | ||
| 28 | |||
| 29 | /// A uniform float in [0, 1) from the top 24 bits of one draw; every value is exactly | ||
| 30 | /// representable. | ||
| 31 | float NextFloat(); | ||
| 32 | |||
| 33 | /// A uniform double in [0, 1) with 53 random bits from two draws. | ||
| 34 | double NextDouble(); | ||
| 35 | |||
| 36 | /// A uniform double in (0, 1], never zero, for logarithms. | ||
| 37 | double NextDoubleOpenBelow(); | ||
| 38 | |||
| 39 | private: | ||
| 40 | U32x2 key_; | ||
| 41 | U32x4 counter_; | ||
| 42 | U32x4 block_; | ||
| 43 | int used_ = 4; | ||
| 44 | }; | ||
| 45 | |||
| 46 | /// A 64-bit ID as two 32-bit words, for keying `RandomStream` and `Philox4x32` by it. | ||
| 47 | struct IdWords { | ||
| 48 | std::uint32_t low = 0; ///< Bits 0 to 31. | ||
| 49 | std::uint32_t high = 0; ///< Bits 32 to 63. | ||
| 50 | }; | ||
| 51 | |||
| 52 | /// Splits a 64-bit ID into its low and high 32-bit words. | ||
| 53 | 3991044 | constexpr IdWords SplitId(std::uint64_t id) { | |
| 54 | 3991044 | return {static_cast<std::uint32_t>(id), static_cast<std::uint32_t>(id >> 32)}; | |
| 55 | } | ||
| 56 | |||
| 57 | } // namespace terraingen | ||
| 58 |