繁体   English   中英

浮点舍入效果说明

[英]Explanation for floating point rounding effect

#include <stdio.h>
int main() {
    printf("%.14f\n", 0.0001f * 10000000.0f);  // 1
    printf("%.14f\n", 0.001f * 1000000.0f);  // 2
    printf("%.14f\n", 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乘法

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


对于printf("%.14f\\n", 0.0001f * 10000000.0f); // 1 printf("%.14f\\n", 0.0001f * 10000000.0f); // 1

  • 代码0.0001ffloat ,值为 0.00009999999747378751635555145263671875

  • 0.0000999999747378751635555145263671875 * 10000000.0 --> 999.999974737875163555145263671875 --> 舍入到最接近的 10 float -->

  • 1000.0 --> "1000.00000000000000"


对于printf("%.14f\\n", 0.001f * 1000000.0f); // 2 printf("%.14f\\n", 0.001f * 1000000.0f); // 2

  • 代码0.001ffloat ,值为 0.001000000047497451305389404296875

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

  • 1000.00006103515625 --> "1000.00006103515625"


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

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


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


*1在 OP 的样本中,没有舍入误差。 一般来说,用"%f"打印float可以舍入。

回答这个问题的另一种方法是说,你没有得到一个“错误”的答案,两个“正确”答案。 你实际上得到了三个“正确”的答案,其中“正确”的意思是“和预期的一样好”。

类型float只给你大约 7 个十进制数字的精度。 因此,对于 1000 范围内的数字,这是小数点后三位。 所以把程序改成这样:

printf("%.3f\n", 0.0001f * 10000000.0f);
printf("%.3f\n", 0.001f * 1000000.0f);
printf("%.3f\n", 0.01f * 100000.0f);

输出是:

1000.000
1000.000
1000.000

没有差异,所有答案显然都是正确的。

或者,用指数表示法进行计算,小数点前一位,后 6 位。

printf("%.6e\n", 0.0001f * 10000000.0f);
printf("%.6e\n", 0.001f * 1000000.0f);
printf("%.6e\n", 0.01f * 100000.0f);

1.000000e+03
1.000000e+03
1.000000e+03

同样,所有答案都相同。

这可能看起来像是“作弊”:我们碰巧知道在我们可以看到的右边的数字中有一些“有趣”的事情,所以以这种方式压制它们并让它看起来是不是错了好像所有的答案都一样? 我不打算回答这个问题,除了指出当你在做浮点运算时,几乎总是有一些东西在右边,你在四舍五入和抑制——这只是一个问题度。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM