首页 > 解决方案 > C - 对双变量求和会根据其编写方式给出不同的输出

问题描述

我有这些变量:

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。这是为什么呢?

标签: c++cdouble

解决方案


假设您正在英特尔处理器上执行此程序。(当问这样的问题时,你应该总是说明你正在使用哪个编译器,包括版本和命令行开关,以及你在哪个系统上运行程序。)英特尔处理器有 80 位浮点格式,它有 64 位有效位。(有效数是浮点数的小数部分。)

看来您的编译器正在使用处理器的 80 位浮点格式进行中间计算,并且它可能使用 IEEE-754 基本 64 位二进制格式来处理double. 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,等于-b,你得到 8。

double temp = a+b;中,赋值强制 C 实现“丢弃”多余的精度。因此,它必须将结果转换为double具有 53 位有效位的格式。前导位为 2 66,最低有效位为 2 14。2 13到 2 3的位被丢弃,其余位被舍入(在这种情况下不会导致任何变化,因为丢弃的位恰好小于中点)。因此,尽管a+bequals b+8,正如我们在上面看到的,转换b+8为的结果double是 just b。然后添加c到这个产生0。


推荐阅读