Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes AgentRandom uniform int #411

Merged
merged 3 commits into from
Feb 10, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions include/flamegpu/runtime/random/AgentRandom.cuh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef INCLUDE_FLAMEGPU_RUNTIME_RANDOM_AGENTRANDOM_CUH_
#define INCLUDE_FLAMEGPU_RUNTIME_RANDOM_AGENTRANDOM_CUH_

#include <cassert>
#include <limits>

#include "flamegpu/detail/curand.cuh"
#include "flamegpu/detail/StaticAssert.h"
Expand All @@ -24,7 +24,7 @@ class AgentRandom {
__forceinline__ __device__ AgentRandom(detail::curandState *d_rng);
/**
* Returns a float uniformly distributed between 0.0 and 1.0.
* @note It may return from 0.0 to 1.0, where 1.0 is included and 0.0 is excluded.
* @note It may return from 0.0 to 1.0, where 0.0 is included and 1.0 is excluded.
* @note Available as float or double
*/
template<typename T>
Expand Down Expand Up @@ -69,11 +69,23 @@ __forceinline__ __device__ AgentRandom::AgentRandom(detail::curandState *d_rng)
*/
template<>
__forceinline__ __device__ float AgentRandom::uniform() const {
return curand_uniform(d_random_state);
// 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<uint32_t>((static_cast<uint64_t>(1) << std::numeric_limits<float>::digits) - 1);
constexpr auto DIVISOR = static_cast<float>(1) / (static_cast<uint32_t>(1) << std::numeric_limits<float>::digits);
return (val & MASK) * DIVISOR;
}
template<>
__forceinline__ __device__ double AgentRandom::uniform() const {
return curand_uniform_double(d_random_state);
// 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<int>(iRan1)*M_RAN_INVM32 + (0.5 + M_RAN_INVM52 / 2) + static_cast<int>((iRan2) & 0x000FFFFF) * M_RAN_INVM52);
}

/**
Expand Down Expand Up @@ -109,7 +121,7 @@ __forceinline__ __device__ T AgentRandom::uniform(T min, T max) const {
DTHROW("Invalid arguments passed to AgentRandom::uniform(), %lld > %lld\n", static_cast<int64_t>(min), static_cast<int64_t>(max));
}
#endif
return static_cast<T>(min + (max - min) * uniform<float>());
return static_cast<T>(min + (1 + max - min) * uniform<float>());
}
template<>
__forceinline__ __device__ int64_t AgentRandom::uniform(const int64_t min, const int64_t max) const {
Expand All @@ -118,7 +130,7 @@ __forceinline__ __device__ int64_t AgentRandom::uniform(const int64_t min, const
DTHROW("Invalid arguments passed to AgentRandom::uniform(), %lld > %lld\n", static_cast<int64_t>(min), static_cast<int64_t>(max));
}
#endif
return static_cast<int64_t>(min + (max - min) * uniform<double>());
return static_cast<int64_t>(min + (1 + max - min) * uniform<double>());
}
template<>
__forceinline__ __device__ uint64_t AgentRandom::uniform(const uint64_t min, const uint64_t max) const {
Expand All @@ -127,7 +139,7 @@ __forceinline__ __device__ uint64_t AgentRandom::uniform(const uint64_t min, con
DTHROW("Invalid arguments passed to AgentRandom::uniform(), %lld > %lld\n", static_cast<int64_t>(min), static_cast<int64_t>(max));
}
#endif
return static_cast<uint64_t>(min + (max - min) * uniform<double>());
return static_cast<uint64_t>(min + (1 + max - min) * uniform<double>());
}
template<>
__forceinline__ __device__ float AgentRandom::uniform(const float min, const float max) const {
Expand Down