浮点舍入效果说明

#include <stdio.h>
int main() {
    printf("%.14fn", 0.0001f * 10000000.0f);  // 1
    printf("%.14fn", 0.001f * 1000000.0f);  // 2
    printf("%.14fn", 0.01f * 100000.0f);  // 3
    return 0;
}

神箭

这段代码的输出是:

1000.00000000000000
1000.00006103515625
1000.00000000000000

我知道,小数不能用浮点数准确表示。但是为什么第 1 行和第 3 行计算正确,而第 2 行却没有?你对这里发生的事情有清楚的解释吗?

回答

有时累积舍入(在 OP 样本中每个 3 步)的结果与数学/十进制相同,有时则不同。@史蒂夫峰会,@史蒂夫峰会


详细说明这里发生了什么?

每行代码有 3 个潜在舍入步骤:

  • 源代码到float. 回忆一下常见float的形式: some_limited_integer * 2 some_power

  • float 乘以四舍五入

  • 打印float四舍五入到 14 位小数*1


为了 printf("%.14fn", 0.0001f * 10000000.0f); // 1

  • 代码0.0001ffloat0.0000999999974737875163555145263671875

  • 0.0000999999747378751635555145263671875 * 10000000.0 --> 999.999974737875163555145263671875 --> 最接近的 100 float--> 0

  • 1000.0 --> "1000.00000000000000".


为了 printf("%.14fn", 0.001f * 1000000.0f); // 2

  • 代码0.001ffloat0.001000000047497451305389404296875

  • 0.001000000047497451305389404296875 * 1000000.0 --> 1000.000047497451305389404296875 --> 四舍五入到最接近的float--> 100610503。

  • 1000.00006103515625 --> "1000.00006103515625".


在#1 中,四舍五入是向下的,然后向上 - 趋于取消。
在 #2 中,四舍五入是向上和向上的 - 导致明显的双舍入效果。

粗略地说,每一步都可能注入高达 1/2 ULP 的错误。


其他注意事项: 1) 替代舍入模式。以上使用舍入到最近。2)弱库。以上假定一个质量printf()


*1在 OP 的样本中,没有舍入误差。一般情况下,float"%f"罐头印刷。


以上是浮点舍入效果说明的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>