我的问题是是否所有整数值都保证具有完美的双重表示。
考虑以下打印“Same”的代码示例:
// Example program
#include <iostream>
#include <string>
int main()
{
int a = 3;
int b = 4;
double d_a(a);
double d_b(b);
double int_sum = a + b;
double d_sum = d_a + d_b;
if (double(int_sum) == d_sum)
{
std::cout << "Same" << std::endl;
}
}
这对于任何架构、任何编译器、任何 a
和 b
的值是否都保证是正确的?是否将任何整数 i
转换为 double
,总是表示为 i.0000000000000
而不是例如 i.000000000001
?
我尝试了其他一些数字,它总是正确的,但无法找到任何关于这是巧合还是设计的信息。
注意:这与 这个问题 不同(除了语言),因为我将两个整数相加。
原文由 Thomas 发布,翻译遵循 CC BY-SA 4.0 许可协议
免责声明(由 Toby Speight 建议):尽管 IEEE 754 表示非常普遍,但允许实现使用满足语言要求的任何其他表示。
双精度数以
mantissa * 2^exponent
的形式表示,即某些位用于双精度数的非整数部分。分数中的部分也可以通过使用删除点后所有数字的指数来表示整数。
例如 2,9979 · 10^4 = 29979。
由于常见的
int
通常是 32 位,因此您可以将所有int
s 表示为 double,但对于 64 位整数,这当然不再适用。更准确地说(正如 LThode 在评论中指出的那样):IEEE 754 双精度可以保证最多 53 位(52 位有效位 + 隐式前导 1 位)。答:32 位整数是可以的,64 位整数不行。
(这对于服务器/桌面通用 CPU 环境是正确的,但其他架构的行为可能会有所不同。)
正如 Malcom McLean 所说的那样, 实际答案 是:64 位双精度数对于几乎所有可能在现实生活中计算事物的整数来说是一种足够的整数类型。
对于有经验的人,试试 这个:
子 问题:关于分数差异的问题。是否有可能有一个整数转换为与正确值相差一个分数的双精度数,但由于四舍五入而转换回相同的整数?
答案是否定的,因为任何来回转换为相同值的整数实际上都以双精度表示相同的整数值。对我来说,最简单的解释(ilkkachu 建议)是使用指数
2^exponent
步长必须始终是 2 的幂。因此,在最大的 52(+1 符号)位整数之外,永远不会有两个距离小于 2 的 double 值,从而解决了舍入问题。