【问题标题】:iOS - rounding a float with roundf() is not working properlyiOS - 使用 roundf() 舍入浮点数无法正常工作
【发布时间】:2023-03-26 06:25:01
【问题描述】:

我在 iPhone 应用程序中舍入浮点数时遇到问题。

float f=4.845;
float s= roundf(f * 100.0)/100;
    NSLog(@"Output-1: %.2f",s);
      s= roundf(484.5)/100;
    NSLog(@"Output-2: %.2f",s);

Output-1: 4.84
Output-2: 4.85

让我知道这有什么问题以及如何解决。

【问题讨论】:

  • 你期待什么输出?
  • 你想做什么??您使用的是浮点数,而不是实数
  • NSLog(@"%f", 4.845f * 100);NSLog(@"%f", 484.5f);看看他们不相等
  • 我已经通过解决方案解决了这个问题 NSString* str=[NSString stringWithFormat:@"%.2f",(f*100)];浮动 s=roundf([str floatValue]);

标签: iphone objective-c math calc


【解决方案1】:

问题是您还没有意识到浮点的固有问题之一:大多数数字无法精确表示这一事实(a)

这意味着 4.845 实际上很可能是类似于 4.8449999999999 的东西,当你将它四舍五入时,它会给你 4.84 而不是你所期望的 4.85

你最终得到的值也取决于如何你计算它,这就是你得到不同结果的原因。

当然,如果没有权威的What Every Computer Scientist Should Know About Floating-Point Arithmetic,SO 上的浮点“不准确”答案将是不完整的。


(a) 在 IEEE754 中,只有在某个相似范围内的 2 的精确幂之和才能精确呈现。因此,例如,484.5

256 + 128 + 64 + 32 + 4 + 0.5 (2<sup>8</sup> + 2<sup>7</sup> + 2<sup>6</sup> + 2<sup>5</sup> + 2<sup>2</sup> + 2<sup>-1</sup>)。

有关 IEEE754 格式的更详细信息,请参阅 this answer


至于解决它,你有几个选择。一种是使用double 而不是float。这为您提供了更高的精度和更大的数字范围,但只会将问题移得更远,而不是真正解决它。由于0.1 是 IEEE754 中的重复分数,没有个位数(小于无穷大)可以准确地表示它。

另一种选择是使用自定义库,如大十进制类型,它可以表示任意精度的小数(这不是像某些人不建议的那样无限精度,因为它受内存限制) .这将减少由二进制/十进制不匹配引起的错误。

您可能还想查看NSDecimalNumber - 这不会为您提供任意精度,但它确实提供了具有精确十进制表示的大范围。

仍然会有你无法表示的数字,例如 PI 或 2 的平方根或任何其他无理数,但它应该涵盖大多数情况。如果您真的需要处理这些其他值,则需要切换到符号数字表示。

【讨论】:

  • 在Objective-C中,你可以使用NSDecimalNumber来避免这种问题。它不是“大十进制类型”,而是精确地表示最多 38 位的十进制数。
  • 是的,我们可以用 NSDecimalNumber 解决它,但我已经通过解决方案解决了它 NSString* str=[NSString stringWithFormat:@"%.2f",(f*100)];浮动 s=roundf([str floatValue]);
【解决方案2】:

484.5 可以完全表示为浮点数不同* 4.845 表示为4.8449998(如果您想尝试其他数字,请参阅this calculator)。乘以 100 使数字保持在 484.49998,正确舍入为 484


* 精确表示是可能的,因为它的小数部分 0.5 是 2 的幂(即 2^-1)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多