我有这些变量:
double a = 5;
double b = 1E20;
double c = -b;
我这样总结他们:
double temp = a+b;
double result = temp+c;
结果等于0,正如预期的那样,因为'b'与'a'相比是一个很大的数字,因此,结果与b的数字完全没有区别,然后用'c'减去它,即与“ b”相同,但为负,则为0。 但是,如果我这样尝试:
double result = (a+b)+c;
结果实际上是8。为什么呢?
答案 0 :(得分:2)
大概您正在Intel处理器上执行此程序。 (在问这样的问题时,您应始终声明使用的是哪个编译器,包括版本和命令行开关,以及在哪个系统上运行程序。)Intel处理器具有80位浮点格式,具有64位有效位。 (有效数字是浮点数的小数部分。)
您的编译器似乎正在使用处理器的80位浮点格式进行中间计算,并且double
可能正在使用IEEE-754基本64位二进制格式。 C标准允许C实现以比标称类型更大的范围和精度来计算浮点表达式。这意味着,当编译器正在评估(或生成要评估的代码)double
表达式时,允许使用80位类型。
当将浮点表达式分配给对象或显式转换为浮点类型时,C标准要求C实现“舍弃”多余的精度。
以上内容使我们能够看到发生了什么。 1e20
代表10 20 ,它是2 66 和2 67 之间的数字。以二进制形式编写,其前导位位于值2 66 的位置。由于80位格式的有效位为64位,因此可以表示为格式的最低有效位在位置2 3 (具有3到66的位为64位)。在b = 1e20
之后,将5加到b
时,结果必须四舍五入以适合2 66 到2 3 (是8)。这导致将数字四舍五入到下一个8的倍数。因此,由于四舍五入,b+5
与b+8
的结果相同。然后,当您添加等于c
的{{1}}时,得到8。
在-b
中,赋值强制C实现“舍弃”多余的精度。因此,它必须将结果转换为double temp = a+b;
格式,该格式具有53位有效数字。前导位为2 66 ,最低有效位为2 14 。 2 13 到2 3 的位被舍弃,其余的位被舍入(在这种情况下,这不会引起任何变化,因为丢弃的位碰巧少了比中点)。因此,尽管double
等于a+b
,如我们上面所见,将b+8
转换为b+8
的结果仅为double
。然后将b
加上0。