Meh*_*dad -5 c floating-point division ieee-754
我跑的时候
printf("%.8f\n", 971090899.9008999);
printf("%.8f\n", 9710908999008999.0 / 10000000.0);
Run Code Online (Sandbox Code Playgroud)
我明白了
971090899.90089989
971090899.90089977
Run Code Online (Sandbox Code Playgroud)
我知道为什么两者都不准确,但我不明白为什么第二个与第一个匹配?
我认为基本的算术运算(+ - */)总是尽可能准确...
第一个数字不是第二个数字比第二个更精确的结果吗?
小智 10
根据您使用的数字并基于标准的IEEE 754浮点标准判断,分区的左侧似乎太大而不能完全包含在64位双精度的尾数(有效数字)中.
在开始出血精度之前,你有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位二进制这两个候选的是表示的,两者都是从所述源值等距离,9710908999008999.通常的舍入模式是舍入到最接近的,领带到偶数,这意味着与偶数位低的候选应选择,这是9710908999009000(带有效数0x1.1400298aa8174),不9710908999008998(带有效数0x1.1400298aa8173).(IEEE 754定义了另一种舍入到最近的模式:tie-to-away,它选择具有较大幅度的候选者,这又是9710908999009000.)
C标准允许一些转换松弛; 这两个候选者中的任何一个符合C标准,但良好的实现也符合IEEE 754.