【问题标题】:Unexpected value printed when using %.1f使用 %.1f 时打印的意外值
【发布时间】:2013-03-21 15:10:21
【问题描述】:

我试图将浮点数显示到小数点后一位。我得到了以下意想不到的结果:

代码:

float a = 1.25;
float b = 1.35;

NSLog(@"1.25 -> %.1f\n1.35 -> %.1f",a,b);

输出:

1.25 -> 1.2

1.35 -> 1.4

预期输出:

1.25 -> 1.3

1.35 -> 1.4

或:

1.25 -> 1.2

1.35 -> 1.3

这仅仅是由于二进制和十进制之间的内部转换吗?如果是这样,我如何获得预期的行为?

我使用的是 Xcode 4.6。

编辑:好的,感谢 TonyK 和 H2CO3,这是由于小数的二进制表示。

float a = 1.25;
float b = 1.35;
NSLog(@"1.25 -> %.30f\n1.35 -> %.30f",a,b);

1.25 -> 1.250000000000000000000000000000

1.35 -> 1.350000000000000088817841970013

很多很好的信息,但据我所知,没有人解决第二个问题:我如何获得预期的行为?

Rounding numbers in Objective-C 是一个完全不同的问题。

【问题讨论】:

  • 这涉及到所有的 C 语言,而不仅仅是 Objective C。你得到什么取决于系统,1.25 可以打印为 1.2 或 1.3。

标签: objective-c c floating-point


【解决方案1】:

1.35 是 27/20,二进制是

1.01 0110 0110 0110 0110 0110 0110....

float 在大多数系统上都有 23 位尾数(不包括隐含的前导 1.),因此它会向上取整为

1.01 0110 0110 0110 0110 0110 1

(因为 0110 明确大于 1000 的一半)。因此,当printf 看到它时,它严格大于 1.35。因此是 1.4。

对于 1.25,这完全可以用二进制表示为

1.01

所以printf 看到了它的确切值。但它应该如何围绕 1.25 呢?我们在学校被教导将 5 到 10 舍入。但大多数现代系统在硬件级别使用称为“舍入到偶数”的默认舍入模式,因为它减少了累积舍入误差的影响。这意味着,当一个数字恰好在两个最近的四舍五入候选之间时,它会四舍五入到偶数候选。

所以看来print 正在使用“四舍五入”进行十进制输出!我在this ideone link 检查了这个假设,确实 1.75 被四舍五入到 1.8。这对我来说是一个惊喜,但不是一个大惊喜。

【讨论】:

  • 感谢您努力挖掘完整的二进制表示。 +1。
【解决方案2】:

这是因为浮点数并不精确。 %.1f 将数字 四舍五入 打印到小数点后一位,然而,1.35 似乎不能精确地表示为 1.2500000,而是一个稍小的数字可以。

在此处了解此行为:What every computer scientist should know about floating-point numbers

【讨论】:

  • 1.25 = 5/4 可以精确表示,因为 4 是 2 的幂。不能精确表示的是 1.35 = 27/20。
  • @TonyK 对,但是为什么它被截断而不是四舍五入?
  • 好的,谢谢 TonyK 和 H2CO3。您可能对我的编辑感兴趣,该编辑显示 %.30f 的行为作为演示。解决此问题以获得一致行为的常用方法是什么?
猜你喜欢
  • 2018-04-23
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
  • 2018-05-23
  • 2018-03-26
  • 1970-01-01
  • 2020-09-22
  • 2013-03-31
相关资源
最近更新 更多