【发布时间】:2018-12-09 18:05:17
【问题描述】:
我注意到在 Visual Studio 中将 double 添加到 long long 时会出现精度错误。例如:
long long a = 44981600439878676;
double b = 234567890;
a += b;
a 的结果是 44981600674446560 但应该是 44981600674446566。x32 和 x64 都会发生这种情况。
但是以下返回正确的值:
long long a = 44981600439878676;
double b = 234567890;
a += (long long)b;
我注意到在反汇编中,在没有显式转换的第一种情况下,有
0116A892 call __ltod3 (011619DDh)
0116A897 addsd xmm0,mmword ptr [b]
0116A89C call __dtol3 (01161A05h)
而在第二种情况下,__ltod3 未被调用。我正在用 VC++ 编译器解释这一点,默认情况下首先将 long long 转换为 double,然后再将 double 转换为 long long,因为 double 类型比 long long 更简单。这样,由于 __ltod3 和 int64 包含的值太大,我们会丢失精度。但另一方面,a 是左值,在这种情况下,因为编译器知道输出会是 long long,所以在加法过程中,看起来没有必要先将左侧转换为 double,然后再转换为 long long。此外,很容易有人犯错误并忽略显式转换,因为精度错误只会对某些数字变得可见。
这种双重转换是 C++ 标准的一部分还是 VS 的实现?
【问题讨论】:
-
double 的精度低于 long long。
-
您应该能够自己解决这个问题,在您尝试围绕以下两个事实进行思考之后:1.
sizeof(double)与sizeof(long long)相同。 2)double似乎能够表示比 long long 更大的值,例如1e100,或 1 后跟一百个零。现在,问问自己这怎么可能,如果long long和double占用相同的字节数,那么您应该能够找出问题的答案。 -
我只是想知道在添加之后最终结果是否会存储在 long long 中,为什么左侧默认转换为 double 然后又转换为 long long?如果我希望默认情况下不丢失精度怎么办。在复杂的代码中,可能有太多地方需要检查是否缺少显式转换。
-
这就是 c++ 算术的工作原理,您必须始终牢记这一点。这也是为什么隐式转换是邪恶的。
标签: c++ precision long-integer assign