有效地将int除以intmax

Cyg*_*sX1 4 c++

我有一个整数类型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.

Ted*_*gmo 5

这听起来像是一项工作:

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