我有一个可耻幼稚的问题:什么是一个转换的最佳方式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)
但我想知道是否有更好的方法?
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倍左右。
可以安全地假设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)