为什么我的BigDecimal对象初始化时出现意外的舍入错误?

And*_*ane 20 ruby floating-point rounding bigdecimal floating-point-precision

在Ruby 2.2.0中,为什么:

BigDecimal.new(34.13985572755337, 9)
Run Code Online (Sandbox Code Playgroud)

平等34.0但是

BigDecimal.new(34.13985572755338, 9)
Run Code Online (Sandbox Code Playgroud)

平等34.1398557

请注意,我在64位计算机上运行它.

Tod*_*obs 11

用字符串而不是浮点数初始化

通常,使用Floats无法获得可靠的行为.您错误地使用Float值而不是String值初始化BigDecimals,这会在开头引入一些不精确.例如,在我的64位系统上:

float1 = 34.13985572755337
float2 = 34.13985572755338

# You can use string literals here, too, if your Float can't be properly
# represented. For example:
#
#    BigDecimal.new("34.13985572755337", 9)
#
# would be safer, but Float#to_s works fine with the provided corpus.
bd1 = BigDecimal.new(float1.to_s, 9)
bd2 = BigDecimal.new(float2.to_s, 9)

bd1.to_s
#=> "0.3413985572755337E2"
bd2.to_s
#=> "0.3413985572755338E2"

bd1.to_f == float1
#=> true
bd2.to_f == float2
#=> true
Run Code Online (Sandbox Code Playgroud)

这是参数的内部表示很重要的一种情况.因此,您的里程将根据您初始化对象的方式而有所不同.

  • @muistooshort随意提供您对底层C模块的分析,或者您认为问题可能出现在受影响的口译员身上的任何地方.我为OP的问题提供了一个实用的解决方案,解决方案显然有效.关于*为什么*语言实现者以他们的方式实现事物的问题是偏离主题的,应该作为基于意见的关闭.但是,你肯定有资格获得自行车脱落,但由于SO不是MRI错误跟踪器,我认为一个具体的答案显示如何可靠地初始化BigDecimal*是一个有效的答案.因人而异. (3认同)
  • 对不起,但这甚至没有回答这个问题.Ruby可以很好地存储浮点值`34.13985572755337`,问题是在BigDecimal的内部某处,一些浮点值以奇怪的方式得到了四舍五入.我不认为~0.13计算为值小于34的小不精确度.这个答案是一个完整的解决方案. (2认同)