C-为什么将浮子除以10的功率要比直接键入数字不准确



当我运行

printf("%.8fn", 971090899.9008999);
printf("%.8fn", 9710908999008999.0 / 10000000.0);

我得到

971090899.90089989
971090899.90089977

我知道为什么都不确切,但是我不明白的是为什么第二个匹配第一个
我认为基本的算术操作( - */)总是尽可能准确...
第一个数字不是比第二个数字更准确的结果吗?

从您使用的数字判断,并根据标准IEEE 754浮点标准,看来该部门的左侧太大,无法完全包含在Mantissa中(64位double的显着性。

在开始出现精度之前,您拥有52位纯整数表示。9710908999008999的表示形式中有〜54位,因此它不能正确地拟合 - 因此,截断和近似开始,您的最终数将全部填充。

编辑:正如指出的那样,没有进行数学操作的第一个数字也不适合。但是,由于您在第二次进行额外的数学数量,因此您会引入不存在第一个数字的额外的舍入错误。因此,您也必须考虑到这一点!

评估表达式 971090899.9008999涉及一个操作,一个从十进制到浮点格式的转换。

评估表达式9710908999008999.0 / 10000000.0涉及三个操作:

  • 9710908999008999.0从十进制转换为浮点格式。
  • 10000000.0从十进制转换为浮点格式。
  • 将上述操作的结果分开。

第二个在任何良好的C实施中都应准确,因为结果是可代表的。但是,其他两个添加了舍入错误。

C不需要实现将小数转换为尽可能准确的浮点;它可以放松一些。但是,良好的实现确实会准确地转换,如有必要,请使用额外的精度。因此,971090899.9008999上的单个操作比多个操作产生更准确的结果。

此外,正如我们从评论中学到的那样,OP使用的C实现将9710908999008999.0转换为9710908999008998。这是IEEE-754的规则不正确的,对于常见的往返模式。正确的结果是9710908999009000。这两个候选者均可在IEEE-754 64位二进制中表示,并且两者都与源价值等距,971090899900899999。应选择具有均匀位的候选人,即9710908999009000(具有显着性0x1.1400298AA8174),而不是9710908999008998(具有显着的0x1.1400298AAA8173)。(IEEE 754定义了另一个往返模式:领带到范围,它选择具有更大幅度的候选人,又是9710908999009000。)

C标准允许转化率有些松弛;这两个候选人中的任何一个都符合C标准,但良好的实现也符合IEEE 754。

最新更新