对于相同的精度,"Decimal.quantize" 是否优于 "round"?

Is "Decimal.quantize" better than "round" for the same precision?

我遇到了两种获得浮点数精度的方法——使用 round 或使用 Decimal 包。

我观察到的结果(在 REPL 中尝试了几个例子)都产生了相同的结果:

>>> from decimal import Decimal
>>> 
>>> 1/3
0.3333333333333333
>>> 
>>> round(1/3)
0
>>> Decimal(1)/Decimal(3)
Decimal('0.3333333333333333333333333333')
>>> 
>>> round(1/3, 2)
0.33
>>> (Decimal(1)/Decimal(3)).quantize(Decimal('0.01'))
Decimal('0.33')
>>>

这让我开始考虑使用这两种方法中的哪一种。这两种方法 always 是否以相同的精度给出相同的相同结果?或者我在这里遗漏了什么?

不,他们并不总是给出相同的结果:

>>> (Decimal(645)/Decimal(1000)).quantize(Decimal("0.01"))
Decimal('0.64')

>>> round(645/1000, 2)
0.65

内置 floats 依赖于以 2 为底的 IEEE 754 双精度浮点表示,而十进制使用以 10 为底的表示。如果你真的想精确到小数位,float 将不起作用,因为大多数非周期性非平凡小数不​​在 float 域内。

>>> f'{round(1/3, 2):.64f}'
'0.3300000000000000155431223447521915659308433532714843750000000000'

>>> f'{(Decimal(1)/Decimal(3)).quantize(Decimal("0.01")):.64f}'
'0.3300000000000000000000000000000000000000000000000000000000000000'

我想我能够找出一些可能不同的用例(我会在发现更多差异时在这里更新):

一个用例是 产生循环分数并加回去的除法 ,比如说 10 / 3:

使用 round:

>>> r = round(10/3, 2)
>>> r
3.33
>>> 
>>> sum([r, r, r])
>>> 9.99
>>>

使用 Decimal(案例 1):

>>> Q = Decimal("0.01")
>>> 
>>> d1 = Decimal(10/3)
>>> d1
Decimal('3.333333333333333481363069950020872056484222412109375')
>>> 
>>> sum([d1, d1, d1])
Decimal('10.00000000000000044408920985')
>>> 
>>> sum([d1, d1, d1]).quantize(Q)
Decimal('10.00')
>>>

使用 Decimal(案例 2):

>>> Q = Decimal("0.01")
>>> 
>>> d2 = Decimal(10) / Decimal(3)
>>> d2
Decimal('3.333333333333333333333333333')
>>> 
>>> sum([d2, d2, d2]).quantize(Q)
Decimal('10.00')
>>> 

第二个用例是当您收到的数字的小数位数多于您的精度值(类似于@H.Doebler mentioned in his answer ). Basically exploiting the round_half_to_even概念。假设您已将精度设置为2, 获取 0.1250.145 之类的数量并添加它们,值应该是 0.27:

使用 round:

>>> 0.125 + 0.145 
0.27
>>> 
>>> round(0.125, 2) + round(0.145, 2)
0.26
>>> 

使用 Decimal(案例 1 - 存储量化):(错误

>>> Q = Decimal("0.01")
>>> d1 = Decimal(0.125).quantize(Q) + Decimal(0.145).quantize(Q)
>>> d1
Decimal('0.26')
>>> d1.quantize(Q)
Decimal('0.26')
>>> 

使用 Decimal(案例 2 - 存储原始数据,量化结果):(正确)

>>> Q = Decimal("0.01")
>>> d2 = Decimal(0.125) + Decimal(0.145)
>>> d2
Decimal('0.2699999999999999900079927784')
>>> d2.quantize(Q)
Decimal('0.27')
>>> 

我认为 roundDecimal (case 1) 给出了错误的结果,因为我们四舍五入(quantizingdecimal 的情况下)数字 before 添加,但在情况 2 中,我们在正确表示 Decimal 中的值后进行量化。我想这在很大程度上取决于何时你量化..