如何防止BigDecimal截断结果?

跟进这个问题 :

我想计算1/1048576并得到正确的结果,即0.00000095367431640625。

使用BigDecimal/截断结果:

 require 'bigdecimal' a = BigDecimal.new(1) #=> # b = BigDecimal.new(2**20) #=> # n = a / b #=> # n.to_s('F') #=> "0.000000953674316406" <- should be ...625 

这真让我感到惊讶,因为我觉得BigDecimal会起作用。

为了得到正确的结果,我必须使用具有显式精度的div

 n = a.div(b, 100) #=> # n.to_s('F') #=> "0.00000095367431640625" <- correct 

但我真的不明白那个精确的论点。 为什么我必须指定它以及我必须使用什么值才能获得未截断的结果?

这甚至可以称为“任意精度浮点十进制算术”吗?

此外,如果我通过以下方式计算上述值:

 a = BigDecimal.new(5**20) #=> # b = BigDecimal.new(10**20) #=> # n = a / b #=> # n.to_s('F') #=> "0.00000095367431640625" 

我得到了正确的结果。 为什么?

BigDecimal可以执行任意精度浮点十进制算术,但是它不能自动确定给定计算的“正确”精度。

例如,考虑一下

 BigDecimal.new(1)/BigDecimal.new(3) #  

可以说,在这种情况下没有正确的精度; 正确的使用价值取决于计算所需的准确性。 值得注意的是,在数学意义上,几乎所有的整数除法都会产生一个具有无限十进制扩展的数,因此需要舍入。 如果分数在将其降低到最低项之后,分母的唯一素数因子是2和5,则分数仅具有有限表示。

所以你必须指定精度。 不幸的是,精度参数有点奇怪,因为它似乎是有效位数和小数点后的位数。 这是1/1048576的不同精度

 1 0.000001 2 0.00000095 3 0.000000953 9 0.000000953 10 0.0000009536743164 11 0.00000095367431641 12 0.000000953674316406 18 0.000000953674316406 19 0.00000095367431640625 

对于任何小于10的值,BigDecimal会将结果截断为9位数,这就是为什么精度为10时精度会突然飙升的原因:此时切换为截断为18位(然后舍入为10位有效数字)。


†根据您比较可数无限集的大小的舒适程度。