ruby - 为什么 ruby​​ BigDecimal 表现出类似于 float 的表示不准确性?

标签 ruby floating-point precision bigdecimal

某些 float 在二进制浮点表示中具有固有的不准确性:

> puts "%.50f" % (0.5)  # cleanly representable
0.50000000000000000000000000000000000000000000000000

> puts "%.50f" % (0.1)  # not cleanly representable
0.10000000000000000555111512312578270211815834045410

这是nothing new 。但为什么 ruby​​ 的 BigDecimal 也表现出这种行为?

> puts "%.50f" % ("0.1".to_d)
0.10000000000000000555111512312578270211815834045410

(为了简洁起见,我使用 Rails 简写 .to_d 而不是 BigDecimal.new,这不是 Rails 特定的问题。)

问题:为什么是 "0.1".to_d仍然显示 10-17 左右的错误?我以为BigDecimal的目的明确是为了避免这样的错误吗?

起初我以为这是因为我正在转换一个已经不准确的 float 0.1BigDecimal ,和BigDecimal只是无损地代表了不准确性。但我确保我使用的是字符串构造函数(如上面的代码片段所示),这应该可以避免这个问题。


编辑:

更多调查表明 BigDecimal仍然在内部清晰地表达事物。 (显然,否则这将是一个广泛使用的系统中的一个巨大错误。)下面是一个仍然显示错误的操作示例:

> puts "%.50f" % ("0.1".to_d * "10".to_d)
1.00000000000000000000000000000000000000000000000000

如果表示是有损的,则会显示与上面相同的错误,只是移动了一个数量级。这是怎么回事?

最佳答案

%.50f 说明符采用浮点值,因此在渲染显示之前需要将十进制值转换为浮点值,因此会受到与您相同的浮点噪声的影响获取普通浮点值。

sprintf 和类似 String#% 方法一样,会根据占位符中指定的类型自动进行转换。

要抑制它,您必须使用 .to_s method直接在 BigDecimal 数字上。如果您想要一定数量的位置,它可以采用可选的格式说明符,并且可以将其链接到其他字符串中的 %s 占位符。

关于ruby - 为什么 ruby​​ BigDecimal 表现出类似于 float 的表示不准确性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40050034/

相关文章:

python - 为什么 x <= x 为假?

ruby - 将 Travis Build 设置为 CLI 的插件

ruby-on-rails - 如何将时间字段解析为小时、分钟和秒?

c - float math.cos 不准确

math - float 学有问题吗?

c++ - 可以从 double 分配给 double 的 static_cast<float> 进行优化吗?

plsql - 优雅的 PL/SQL 来比较两个具有不同小数位数的数字

ruby - 是否存在用于匹配哈希的 RSpec2 匹配器?

php - 用PHP加密的openssl需要用Ruby解密

python - 基本的 Python 数字