【问题标题】:ruby floating point errors红宝石浮点错误
【发布时间】:2016-02-18 00:00:11
【问题描述】:

有人能解释一下为什么这里乘以 100 得到的结果不太准确,而乘以 10 两次得到的结果更准确吗?

± % sc
Loading development environment (Rails 3.0.1)
>> 129.95 * 100
12994.999999999998
>> 129.95*10
1299.5
>> 129.95*10*10
12995.0

【问题讨论】:

  • 很可能是由于浮点数的二进制表示。我假设你不能在 base 2 中准确地写 129.95。
  • 有什么线索可以解释为什么这不会发生在我身上?我试图证明这一点,我将上面的 129.95 * 100 输入到 IRB 中,我意外地得到了正确的答案。
  • 回答我自己的问题 - 似乎 Float#to_s 回合。这样做有效: printf("%.50f", 129.95 * 100)

标签: ruby floating-point


【解决方案1】:

如果您以双精度二进制(限制为 53 个有效位)手动进行计算,您会看到发生了什么:

129.95 = 1.0000001111100110011001100110011001100110011001100110 x 2^7

129.95*100 = 1.100101100001011111111111111111111111111111111111111011 x 2^13

这是 56 位有效位,因此四舍五入为 53 位

1.1001011000010111111111111111111111111111111111111111 x 2^13,等于

12994.999999999998181010596454143524169921875

现在 129.95*10 = 1.0100010011011111111111111111111111111111111111111111 x 2^10

这是 54 位有效位,因此四舍五入为 53 位,即 1.01000100111 x 2^10 = 1299.5

现在 1299.5 * 10 = 1.1001011000011 x 2^13 = 12995。

【讨论】:

    【解决方案2】:

    没有与129.95 完全相等的浮点数。所以你的语言使用一个接近它的值。当该值乘以 100 时,结果接近 12995,但它恰好不等于 12995。(它也不完全等于它用来代替 129.95 的原始值的 100 倍。)所以你的解释器打印一个接近(但不等于)129.95 * 100 的值的十进制数,这表明它不完全是 12995。结果129.95 * 10 恰好等于 1299.5。这主要是运气。

    底线是,永远不要期望任何浮点算术都相等,只有“接近”。

    【讨论】:

      【解决方案3】:

      首先:您正在查看结果的字符串表示形式,而不是实际结果本身。如果您真的想要比较这两个结果,则应使用String#% 明确格式化这两个结果,并且应以相同的方式格式化这两个结果。

      其次,这就是二进制浮点数的工作原理。它们是不精确的,它们是有限的,它们是二元的。这三个都意味着你会得到四舍五入的错误,这些错误通常看起来完全随机,除非你碰巧记住了整个 IEEE754 并且可以在睡梦中背诵它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-20
        相关资源
        最近更新 更多