我想计算1/1048576并得到正确的结果,即0.00000095367431640625。
使用BigDecimal
' s /
截断结果:
require 'bigdecimal'
a = BigDecimal.new(1)
#=> #<BigDecimal:7fd8f18aaf80,'0.1E1',9(27)>
b = BigDecimal.new(2**20)
#=> #<BigDecimal:7fd8f189ed20,'0.1048576E7',9(27)>
n = a / b
#=> #<BigDecimal:7fd8f0898750,'0.9536743164 06E-6',18(36)>
n.to_s('F')
#=> "0.000000953674316406" <- should be ...625
这让我感到很惊讶,因为我认为BigDecimal
会起作用。
要获得正确的结果,我必须使用具有明确精度的div
:
n = a.div(b, 100)
#=> #<BigDecimal:7fd8f29517a8,'0.9536743164 0625E-6',27(126)>
n.to_s('F')
#=> "0.00000095367431640625" <- correct
但我并不完全理解 precision 参数。为什么我必须指定它以及我必须使用什么值来获得未截断的结果?
这是否符合&#34;任意精度浮点十进制算术&#34; ?
此外,如果我通过以下方式计算上述值:
a = BigDecimal.new(5**20)
#=> #<BigDecimal:7fd8f20ab7e8,'0.9536743164 0625E14',18(27)>
b = BigDecimal.new(10**20)
#=> #<BigDecimal:7fd8f2925ab8,'0.1E21',9(36)>
n = a / b
#=> #<BigDecimal:7fd8f4866148,'0.9536743164 0625E-6',27(54)>
n.to_s('F')
#=> "0.00000095367431640625"
我确实得到了正确的结果。为什么呢?
答案 0 :(得分:3)
BigDecimal可以执行任意精度浮点十进制算术,但是它无法自动确定给定计算的“正确”精度。
例如,考虑
BigDecimal.new(1)/BigDecimal.new(3)
# <BigDecimal:1cfd748, '0.3333333333 33333333E0', 18(36)>
可以说,在这种情况下没有正确的精度;正确的使用价值取决于计算所需的准确性。值得注意的是,在数学意义上,几乎所有的整数除法都会产生一个具有无限十进制扩展的数字,因此需要舍入。只有在将分数减少到最低项后,分母的唯一素数因子是2和5才有一个有限的表示。
所以你必须指定精度。不幸的是,precision参数有点奇怪,因为它似乎是有效位数和小数点后的位数。这是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位有效数字)
†根据您对可数无限集的大小进行比较的舒适程度。