某些 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.1
至BigDecimal
,和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/