浮点格式的 Python 精度问题



请看下面我在Python 3.6解释器中输入的Python代码:

>>> 0.00225 * 100.0
0.22499999999999998
>>> '{:.2f}'.format(0.00225 * 100.0)
'0.22'
>>> '{:.2f}'.format(0.225)
'0.23'
>>>  '{:.2f}'.format(round(0.00225 * 100.0, 10))
'0.23'

希望你能立即理解我为什么感到沮丧。我正在尝试在我的 GUI 上显示value * 100.0,将完整精度存储在单元格后面,但只显示 2 个小数点(或任何用户的精度设置)。GUI 类似于 Excel 电子表格。

我宁愿不要丢失像0.22222444937645和舍入10之类的精度,但我也不希望像0.00225 * 100.0这样的值显示为0.22

我很想听听处理这种情况的标准方法或针对我的具体情况的补救措施。提前感谢您的任何帮助。

考虑使用十进制模块,该模块"为快速正确舍入的十进制浮点运算提供支持"。 与您的用例相关的Decimal的主要优点是:

  • 十进制数字可以精确表示。相比之下,像1.12.2这样的数字在二进制浮点中没有确切的表示形式。最终用户通常不希望1.1 + 2.2像二进制浮点一样显示3.3000000000000003

  • 精确性延续到算术中。在十进制浮点数中,0.1 + 0.1 + 0.1 - 0.3正好等于零。在二进制浮点中,结果为
    5.5511151231257827e-017。虽然接近于零,但差异阻碍了可靠的相等性检验,并且差异可能会累积。因此,在具有严格相等不变量的会计应用程序中,十进制是首选。

根据您在问题中提供的信息,我不能说迁移到Decimal需要多少大修。但是,如果您正在创建类似电子表格的应用程序并且始终希望保持最大精度,那么您可能希望重构以迟早使用Decimal以避免在面向用户的 GUI 中出现意外数字。

若要获得所需的行为,可能需要更改Decimal实例的舍入模式(默认为ROUND_HALF_EVEN)。

from decimal import getcontext, ROUND_HALF_UP
getcontext().rounding = ROUND_HALF_UP
n = round(Decimal('0.00225') * Decimal('100'), 2)
print(n)  # prints Decimal('0.23')
m = round(Decimal('0.00225') * 100, 2)
print(m)  # prints Decimal('0.23')

也许使用十进制? docs.python.org/2/library/decimal.html

from decimal import *
getcontext().prec = 2
n = Decimal.from_float(0.00225)
m = n * 100
print(n, m)
print(m.quantize(Decimal('.01'), rounding=ROUND_DOWN))
print(m.quantize(Decimal('.01'), rounding=ROUND_UP)

最新更新