从浮点文字构造时出现奇怪的十进制行为

Strange Decimal behavior while constructing from float literal

我期望 2 位小数精度,但是:

>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 2
>>> Decimal(98791.4913)
Decimal('98791.491299999994225800037384033203125')
>>> getcontext()
Context(prec=2, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])

为什么 Decimal 不遵守 Context 精度?

引用自documentation(强调我的)-

If value is a float, the binary floating point value is losslessly converted to its exact decimal equivalent. This conversion can often require 53 or more digits of precision. For example, Decimal(float('1.1')) converts to Decimal('1.100000000000000088817841970012523233890533447265625').

The context precision does not affect how many digits are stored. That is determined exclusively by the number of digits in value. For example, Decimal('3.00000') records all five zeros even if the context precision is only three.

The purpose of the context argument is determining what to do if value is a malformed string. If the context traps InvalidOperation, an exception is raised; otherwise, the constructor returns a new Decimal with the value of NaN.

from same documentation-

The significance of a new Decimal is determined solely by the number of digits input. Context precision and rounding only come into play during arithmetic operations.

文档中给出了很好的例子 -

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

来自documentation

If value is a float, the binary floating point value is losslessly converted to its exact decimal equivalent. This conversion can often require 53 or more digits of precision. For example, Decimal(float('1.1')) converts to Decimal('1.100000000000000088817841970012523233890533447265625').

The context precision does not affect how many digits are stored. That is determined exclusively by the number of digits in value.

...

Context precision and rounding only come into play during arithmetic operations.

强调我的。

您可以使用 Decimal.quantize 方法截断该值:

places = 2
Decimal(98791.4913).quantize(Decimal(10) ** -places) # 98791.49

Context.quantize:

places = 2
getcontext().quantize(Decimal(98791.4913), Decimal(10) ** -places) # 98791.49