我正在尝试编写一个简单的log base 2方法。 我知道在计算机上表示 std::log(8.0( 和 std::log(2.0( 之类的东西很困难。 我也理解 std::log(8.0(/std::log(2.0( 可能会导致值略低于 3.0。 我不明白的是,与直接转换公式相比,为什么将下面的计算结果放入双精度值并将其转换为左值然后将其转换为无符号整数会改变结果。 下面的代码显示了我的测试用例,它在我的 32 位 debian wheezy 机器上反复失败,但在我的 64 位 debian wheezy 机器上反复通过。
#include <cmath>
#include "assert.h"
int main () {
int n = 8;
unsigned int i =
static_cast<unsigned int>(std::log(static_cast<double>(n)) /
std::log(static_cast<double>(2)));
double d =
std::log(static_cast<double>(n)) / std::log(static_cast<double>(2));
unsigned int j = static_cast<unsigned int> (d);
assert (i == j);
}
我也知道我可以使用位移位以更可预测的方式得出我的结果。 我最好奇的是,为什么铸造导致操作的双精度值与将该值粘贴到堆栈上的双精度值并在堆栈上铸造双精度值有任何不同。
在C++中,浮点被允许做这种事情。
一种可能的解释是,除法结果在内部以比double
更高的精度计算,并存储在比double
更高的寄存器中。
将其直接转换为unsigned int
会产生不同的结果,首先将其转换为double
然后转换为unsigned int
。
要确切地了解发生了什么,查看编译器为 32 位情况生成的程序集输出可能会有所帮助。
不用说,您不应该编写依赖于浮点运算精确性的代码。