我有一个整数类型uint32_t,想将其除以的最大值,uint32_t并得到a的结果float(范围为0..1)。
当然,我可以执行以下操作:
float result = static_cast<float>(static_cast<double>(value) / static_cast<double>(std::numeric_limits<uint32_t>::max()))
Run Code Online (Sandbox Code Playgroud)
但是,这实际上是很多转换,而除法本身可能会很昂贵。
Is there a way to achieve the above operation faster, without division and excess type conversions? Or maybe I shouldn't worry because modern compilers are able to generate an efficient code already?
Edit: division by MAX+1, effectively giving me a float in range [0..1) would be fine too.
A bit more context:
I use the above transformation in a time-critical loop, with uint32_t being produced from a relatively fast random-number generator (such as pcg). I expect that the conversions/divisions from the above transformation may have some noticable, albeit not overwhelming, negative impact on the performance of my code.
这听起来像是一项工作:
std::uniform_real_distribution<float> dist(0.f, 1.f);
Run Code Online (Sandbox Code Playgroud)
我相信,这样可以尽可能有效地无偏差地转换到float该范围[0, 1)。如果您希望范围是[0, 1]您可以使用此:
std::uniform_real_distribution<float> dist(0.f, std::nextafter(1.f, 2.f))
Run Code Online (Sandbox Code Playgroud)
这是一个具有非随机数生成器的两个实例的示例,该实例为生成min和max uint32_t:
#include <iostream>
#include <limits>
#include <random>
struct ui32gen {
constexpr ui32gen(uint32_t x) : value(x) {}
uint32_t operator()() { return value; }
static constexpr uint32_t min() { return 0; }
static constexpr uint32_t max() { return std::numeric_limits<uint32_t>::max(); }
uint32_t value;
};
int main() {
ui32gen min(ui32gen::min());
ui32gen max(ui32gen::max());
std::uniform_real_distribution<float> dist(0.f, 1.f);
std::cout << dist(min) << "\n";
std::cout << dist(max) << "\n";
}
Run Code Online (Sandbox Code Playgroud)
输出:
0
1
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以更快地完成操作,而无需进行除法和过多的类型转换?
如果你想手动做一些类似于什么uniform_real_distribution呢(但速度更快,并朝较低的值略微偏),你可以这样定义一个函数:
// [0, 1) the common range
inline float zero_to_one_exclusive(uint32_t value) {
static const float f_mul =
std::nextafter(1.f / float(std::numeric_limits<uint32_t>::max()), 0.f);
return float(value) * f_mul;
}
Run Code Online (Sandbox Code Playgroud)
它使用乘法而不是除法,因为它通常要快一些(比您最初的建议要快),并且只有一种类型转换。这是除法与乘法的比较。
如果您确实希望该范围为[0, 1],则可以执行以下操作,与std::uniform_real_distribution<float> dist(0.f, std::nextafter(1.f, 2.f))产生的结果相比,该值也会偏向于较低的值:
// [0, 1] the not so common range
inline float zero_to_one_inclusive(uint32_t value) {
static const float f_mul = 1.f/float(std::numeric_limits<uint32_t>::max());
return float(value) * f_mul;
}
Run Code Online (Sandbox Code Playgroud)
这是与和比较的基准。uniform_real_distributionzero_to_one_exclusivezero_to_one_inclusive
| 归档时间: |
|
| 查看次数: |
186 次 |
| 最近记录: |