.. _program_listing_file_include_flamegpu_runtime_random_AgentRandom.cuh: Program Listing for File AgentRandom.cuh ======================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/flamegpu/runtime/random/AgentRandom.cuh``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef INCLUDE_FLAMEGPU_RUNTIME_RANDOM_AGENTRANDOM_CUH_ #define INCLUDE_FLAMEGPU_RUNTIME_RANDOM_AGENTRANDOM_CUH_ #include #include "flamegpu/detail/curand.cuh" #include "flamegpu/detail/StaticAssert.h" #include "flamegpu/exception/FLAMEGPUDeviceException.cuh" namespace flamegpu { class AgentRandom { public: __forceinline__ __device__ AgentRandom(detail::curandState *d_rng); template __forceinline__ __device__ T uniform() const; template __forceinline__ __device__ T normal() const; template __forceinline__ __device__ T logNormal(T mean, T stddev) const; __forceinline__ __device__ unsigned int poisson(double mean = 1.0f) const; template __forceinline__ __device__ T uniform(T min, T max) const; private: detail::curandState *d_random_state; }; __forceinline__ __device__ AgentRandom::AgentRandom(detail::curandState *d_rng) : d_random_state(d_rng) { } template<> __forceinline__ __device__ float AgentRandom::uniform() const { // curand naturally generates the range (0, 1], we want [0, 1) // https://github.com/pytorch/pytorch/blob/059aa34b124916dfd761f3cbdb5fa97d7a01fc93/aten/src/ATen/native/cuda/Distributions.cu#L71-L77 uint32_t val = curand(d_random_state); // need just bits constexpr auto MASK = static_cast((static_cast(1) << std::numeric_limits::digits) - 1); constexpr auto DIVISOR = static_cast(1) / (static_cast(1) << std::numeric_limits::digits); return (val & MASK) * DIVISOR; } template<> __forceinline__ __device__ double AgentRandom::uniform() const { // curand naturally generates the range (0, 1], we want [0, 1) // Conversion of High-Period Random Numbers to Floating Point - Jurgen A Doornik // Based on: https://www.doornik.com/research/randomdouble.pdf const uint32_t iRan1 = curand(d_random_state); const uint32_t iRan2 = curand(d_random_state); constexpr double M_RAN_INVM32 = 2.32830643653869628906e-010; constexpr double M_RAN_INVM52 = 2.22044604925031308085e-016; return (static_cast(iRan1)*M_RAN_INVM32 + (0.5 + M_RAN_INVM52 / 2) + static_cast((iRan2) & 0x000FFFFF) * M_RAN_INVM52); } template<> __forceinline__ __device__ float AgentRandom::normal() const { return curand_normal(d_random_state); } template<> __forceinline__ __device__ double AgentRandom::normal() const { return curand_normal_double(d_random_state); } template<> __forceinline__ __device__ float AgentRandom::logNormal(const float mean, const float stddev) const { return curand_log_normal(d_random_state, mean, stddev); } template<> __forceinline__ __device__ double AgentRandom::logNormal(const double mean, const double stddev) const { return curand_log_normal_double(d_random_state, mean, stddev); } __forceinline__ __device__ unsigned int AgentRandom::poisson(const double mean) const { return curand_poisson(d_random_state, mean); } template __forceinline__ __device__ T AgentRandom::uniform(T min, T max) const { static_assert(detail::StaticAssert::_Is_IntType::value, "Invalid template argument for AgentRandom::uniform(T lowerBound, T max)"); #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS if (min > max) { DTHROW("Invalid arguments passed to AgentRandom::uniform(), %lld > %lld\n", static_cast(min), static_cast(max)); } #endif return static_cast(min + (1 + max - min) * uniform()); } template<> __forceinline__ __device__ int64_t AgentRandom::uniform(const int64_t min, const int64_t max) const { #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS if (min > max) { DTHROW("Invalid arguments passed to AgentRandom::uniform(), %lld > %lld\n", static_cast(min), static_cast(max)); } #endif return static_cast(min + (1 + max - min) * uniform()); } template<> __forceinline__ __device__ uint64_t AgentRandom::uniform(const uint64_t min, const uint64_t max) const { #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS if (min > max) { DTHROW("Invalid arguments passed to AgentRandom::uniform(), %lld > %lld\n", static_cast(min), static_cast(max)); } #endif return static_cast(min + (1 + max - min) * uniform()); } template<> __forceinline__ __device__ float AgentRandom::uniform(const float min, const float max) const { #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS if (min > max) { DTHROW("Invalid arguments passed to AgentRandom::uniform(), %f > %f\n", min, max); } #endif return min + (max - min) * uniform(); } template<> __forceinline__ __device__ double AgentRandom::uniform(const double min, const double max) const { #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS if (min > max) { DTHROW("Invalid arguments passed to AgentRandom::uniform(), %f > %f\n", min, max); } #endif return min + (max - min) * uniform(); } } // namespace flamegpu #endif // INCLUDE_FLAMEGPU_RUNTIME_RANDOM_AGENTRANDOM_CUH_