将 uint32_t 转换为 0 和 1 之间的 double

Tom*_*eus 8 c++

我有一个可耻幼稚的问题:什么是一个转换的最佳方式uint32_t,以一个double0和1之间?

我天真的方法是

double myconvert(uint32_t a)
{
    double n = static_cast<double>(std::numeric_limits<uint32_t>::max() - std::numeric_limits<uint32_t>::min());
    return static_cast<double>(a) / n;
}
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有更好的方法?

eer*_*ika 8

std::numeric_limits<uint32_t>::min() 是 0。虽然删除减法不会改进生成的程序集,因为它在编译时已知,但它可以简化函数。

另一个潜在的改进是计算除数的补码并使用乘法。您可能认为优化器会自动进行该转换,但由于 IEEE-754 的严格规则,浮点数通常无法实现。

例子:

return a * (1.0 / std::numeric_limits<uint32_t>::max());
Run Code Online (Sandbox Code Playgroud)

请注意,在用于计算补码的除法中,两个操作数在编译时都是已知的,因此除法是预先计算的。

正如你可以看到这里,GCC也不会自动做了优化。如果您-ffast-math以 IEEE-754 一致性为代价使用它,则可以

我查了Agner Fog的指令,随机选择了Zen3架构,双除法的延迟比乘法大3倍左右。


Adr*_*ica 6

可以安全地假设std::numeric_limits<uint32_t>::min()为零(哪个无符号整数小于这个?),因此您可以大大简化您的公式:

double myconvert(uint32_t a)
{
    return static_cast<double>(a) / std::numeric_limits<uint32_t>::max();
}
Run Code Online (Sandbox Code Playgroud)


Bat*_*eba 5

1.0 * a / std::numeric_limits<uint32_t>::max()

是一种方式。