为什么 ruby BigDecimal 显示类似于 float 的表示不准确?
Why does ruby BigDecimal show representation inaccuracy similar to float?
某些浮点数在二进制浮点表示中存在固有的不准确性:
> puts "%.50f" % (0.5) # cleanly representable
0.50000000000000000000000000000000000000000000000000
> puts "%.50f" % (0.1) # not cleanly representable
0.10000000000000000555111512312578270211815834045410
这是nothing new. But why does ruby's BigDecimal
也表现出这种行为?
> puts "%.50f" % ("0.1".to_d)
0.10000000000000000555111512312578270211815834045410
(我使用 rails shorthand .to_d
而不是 BigDecimal.new
只是为了简洁,这不是 rails具体问题。)
问题:为什么"0.1".to_d
仍然显示10-17数量级的错误?我以为 BigDecimal
的目的是明确避免这样的错误?
起初我以为这是因为我正在将一个已经不准确的浮点数 0.1
转换为 BigDecimal
,而 BigDecimal
只是无损地表示不准确。但我确保我使用的是字符串构造函数(如上面的代码片段所示),这应该可以避免这个问题。
编辑:
更多的调查表明 BigDecimal
仍然在内部清晰地表示事物。 (很明显,因为否则这将是一个非常广泛使用的系统中的 巨大 错误。)这是一个仍然会显示错误的操作示例:
> puts "%.50f" % ("0.1".to_d * "10".to_d)
1.00000000000000000000000000000000000000000000000000
如果表示有损,则会显示与上述相同的错误,只是偏移了一个数量级。这是怎么回事?
%.50f
说明符采用浮点值,因此十进制值在呈现以显示之前需要转换为浮点值,因此会受到与普通浮点噪声相同的影响浮点值。
sprintf
和朋友一样,喜欢String#%
方法,根据占位符指定的类型自动进行转换。
要抑制它,您必须直接在 BigDecimal 数字上使用 .to_s
method。如果您想要一定数量的位置,它可以采用可选的格式说明符,并且可以将其链接到其他字符串中的 %s
占位符。
某些浮点数在二进制浮点表示中存在固有的不准确性:
> puts "%.50f" % (0.5) # cleanly representable
0.50000000000000000000000000000000000000000000000000
> puts "%.50f" % (0.1) # not cleanly representable
0.10000000000000000555111512312578270211815834045410
这是nothing new. But why does ruby's BigDecimal
也表现出这种行为?
> puts "%.50f" % ("0.1".to_d)
0.10000000000000000555111512312578270211815834045410
(我使用 rails shorthand .to_d
而不是 BigDecimal.new
只是为了简洁,这不是 rails具体问题。)
问题:为什么"0.1".to_d
仍然显示10-17数量级的错误?我以为 BigDecimal
的目的是明确避免这样的错误?
起初我以为这是因为我正在将一个已经不准确的浮点数 0.1
转换为 BigDecimal
,而 BigDecimal
只是无损地表示不准确。但我确保我使用的是字符串构造函数(如上面的代码片段所示),这应该可以避免这个问题。
编辑:
更多的调查表明 BigDecimal
仍然在内部清晰地表示事物。 (很明显,因为否则这将是一个非常广泛使用的系统中的 巨大 错误。)这是一个仍然会显示错误的操作示例:
> puts "%.50f" % ("0.1".to_d * "10".to_d)
1.00000000000000000000000000000000000000000000000000
如果表示有损,则会显示与上述相同的错误,只是偏移了一个数量级。这是怎么回事?
%.50f
说明符采用浮点值,因此十进制值在呈现以显示之前需要转换为浮点值,因此会受到与普通浮点噪声相同的影响浮点值。
sprintf
和朋友一样,喜欢String#%
方法,根据占位符指定的类型自动进行转换。
要抑制它,您必须直接在 BigDecimal 数字上使用 .to_s
method。如果您想要一定数量的位置,它可以采用可选的格式说明符,并且可以将其链接到其他字符串中的 %s
占位符。