c - 四舍五入甚至没有始终如一地应用?

标签 c floating-point printf rounding

(上下文:我正在为嵌入式应用程序编写一个轻量级的 printf(),我希望它在实用时表现得像真正的 printf()。)

我知道 gcc 和其他行为良好的库使用“四舍五入”(又名“银行家四舍五入”)来防止以下情况下的统计偏差:

printf("%0.0f %0.0f %0.0f %0.0f\n", 0.5, 1.5, 2.5, 3.5);
=> 0 2 2 4

令我惊讶的是,相同的舍入规则并未应用于其他精度:

printf("%0.1f %0.1f %0.1f %0.1f\n", 0.05, 0.15, 0.25, 0.35);
=> 0.1 0.1 0.2 0.3

这是预期的行为吗?我本以为:

=> 0.0 0.2 0.2 0.4

精通数值计算的人可以解释哪种行为是理想的行为,为什么?

(注意:有关实际示例,请参阅 http://rextester.com/IUXDW9788。)

最佳答案

区别在于输入的数字,而不是格式。

0.5、1.5、2.5、3.5 和 0.25 都可以在 IEEE 754 64 位二进制中精确表示,这是 C double 的最可能实现,因此四舍五入规则适用。

最接近 0.05 的可表示值是 0.05000000000000000277555756156289135105907917022705078125,比 0.0 更接近 0.1

最接近 0.15 的可表示值是 0.1499999999999999944488848768742172978818416595458984375,比 0.2 更接近 0.1。

最接近 0.35 的可表示值是 0.34999999999999997779553950749686919152736663818359375,比 0.4 更接近 0.3。

四舍五入规则仅适用于恰好两个可能结果之间的数字,而不适用于与其中一个可能结果比另一个可能结果稍微更接近的数字。

关于c - 四舍五入甚至没有始终如一地应用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43829570/

相关文章:

c - 修复 BAC 程序

c - 为什么 gcc 返回 0 而不是堆栈分配变量的地址?

c++ - 在整数数组上移动时指针如何工作

将字符数组转换为具有 2 个小数位的 float

c 格式字符串 : printf argument containing format specifiers

c - 为什么从以下代码中删除 sprintf() 会导致段错误?如何处理?

c - 如何检测 C 中的一个或多个键的笔划?

在 C 中实现 round() 的简洁方法?

C - pow() 奇怪的行为

ios - 如何在 Xcode 管理器中访问设备日志(不是崩溃报告)