【问题标题】:Why does printf output float 1.45 with one decimal place, and 1.445 with two decimal places in different behaviors? [duplicate]为什么 printf 输出浮点 1.45 有一位小数,而 1.445 有两位小数在不同的行为中? [复制]
【发布时间】:2020-12-27 04:37:30
【问题描述】:
printf("%.1f, %.2f", 1.45, 1.445);

输出

1.4、1.45

1.45 是切片的,但 1.445 是四舍五入的。

我发现了这个, Why printf round floating point numbers? 这解释了规范建议对浮点数进行舍入。

编辑: 我使用 VS2017(在 C++ 项目中)和 Dev-C 对其进行了测试。

【问题讨论】:

  • 假设您的实现像许多人一样使用 IEEE-754 浮点数,这两个值都没有精确的表示。因此,您在源代码中编写为1.4 的常量被编译为接近但不等于1.4 的双精度值。之后它以哪种方式循环是偶然的。
  • 试试printf("%.55f\n%.55f\n", 1.45, 1.445);看看实际数字是多少。
  • 题目在题目名称中

标签: c++ c floating-point specifications


【解决方案1】:

[已编辑:我最初并没有将它们打印到足够荒谬的精度水平,因此答案在结果背后给出了错误的推理。]

如果您将它们打印到荒谬的精确度,那么真相就会出来:

#include <stdio.h>
printf("%20.20f, %20.20f", 1.45, 1.445);

结果:

1.44999999999999995559, 1.44500000000000006217

因此,转换后,1.45 最终会比 1.45一点,而 1.445 会比 1.445 稍微大于一点。

所以,当然,当我们舍入 1.45 时,它会向下舍入,但当我们舍入 1.445 时,它会向上舍入。

【讨论】:

  • 次要:不需要宽度。 "%.20f" 足以证明你的优点。
  • 谢谢,我也有同样的假设。但是我只调试了7或8位小数的double值,并没有看到“真相”,哈哈。
  • @Zhang: 7 或 8 足以看出 float 的问题,但 double 的小数精度通常在 16 位左右,所以我们希望一切都看起来“完美”到 8 个地方(甚至更远)。另一方面,没有办法直接用printf打印出float——如果你尝试传递float,它会在到达printf之前被提升为double(并且在极少数情况下,这种额外的转换水平可能会导致更多的混乱)。
【解决方案2】:

double 编码大约 264 个不同的值正好

1.45 和 1.445 都不在这组 264 个值中,因为这些十进制值不能表示为 dyadic rational 值:一些整数乘以 2 的幂。

使用邻近值代替 1.45、1.445:

 1.45  --> 6530219459687219 * 2^-52 or about 1.449999999999999955591079... 
 1.445 --> 6507701461550367 * 2^-52 or about 1.445000000000000062172489...  or 

OP 的 printf() 做得很好,并且正确地舍入了这些值。

printf("%.1f\n%.2f", 1.45, 1.445);
1.4     
1.45

【讨论】:

  • 1.445000000000000062172489 的四舍五入为 1.44(最多 2 个十进制数)。我错了吗?
  • @KrishnaKanthYenumula 是的,您对默认舍入模式是错误的,1.445000000000000062172489 大于 1.445,因此将向上舍入到 1.45
  • @KrishnaKanthYenumula 取决于舍入模式。通常是四舍五入到最近的(关系到偶数)。 1.4450000000000000062172489... 比 1.44 更接近 1.45。
猜你喜欢
  • 1970-01-01
  • 2023-01-08
  • 1970-01-01
  • 2022-01-18
  • 2015-02-17
  • 2018-03-04
  • 2022-01-11
  • 2013-05-01
相关资源
最近更新 更多