This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: decimal ROUND_HALF_UP not according to spec for 9.95 to 10.0
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: felix.engelmann, mark.dickinson
Priority: normal Keywords:

Created on 2018-02-22 10:02 by felix.engelmann, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (2)
msg312546 - (view) Author: (felix.engelmann) Date: 2018-02-22 10:02
As described in https://www.python.org/dev/peps/pep-0327/#rounding-algorithms
round-half-up: If the discarded digits represent greater than or equal to half (0.5) then the result should be incremented by 1; otherwise the discarded digits are ignored.

Rounding 9.95 to 1 decimal with ROUND_HALD_UP results in 9.9 instead of 10.0:
 
Decimal(9.95).quantize(Decimal('1.1'),ROUND_HALF_UP)
Out[49]: Decimal('9.9')

It does not matter at wich position this rounding with influence on another digit happens:

Decimal(9.995).quantize(Decimal('1.11'),ROUND_HALF_UP)
Out[50]: Decimal('9.99')

It is a specific problem with the 5, because 9.96 works as expected

Decimal(9.96).quantize(Decimal('1.1'),ROUND_HALF_UP)
Out[40]: Decimal('10.0')

System:

Python 3.6.4

import decimal
decimal.__version__ : '1.70'
msg312547 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2018-02-22 10:12
This isn't a bug. When you do `Decimal(9.95)`, you're converting the binary floating-point number `9.95` to a `Decimal` instance. The conversion is performed exactly, with no change in the value. But the *input* to the conversion, the float `9.95` can't be stored exactly in IEEE 754 binary64 format, so what you end up with is something very slightly smaller.

>>> from decimal import Decimal
>>> Decimal(9.95)
Decimal('9.949999999999999289457264239899814128875732421875')

That's the reason that it rounds down.

Good practice is to create your Decimal instances from strings rather than floats.

>>> Decimal(9.95).quantize(Decimal('1.1'),ROUND_HALF_UP)
Decimal('9.9')
>>> Decimal('9.95').quantize(Decimal('1.1'),ROUND_HALF_UP)
Decimal('10.0')
History
Date User Action Args
2022-04-11 14:58:58adminsetgithub: 77089
2018-02-22 10:12:18mark.dickinsonsetstatus: open -> closed

nosy: + mark.dickinson
messages: + msg312547

resolution: not a bug
stage: resolved
2018-02-22 10:02:31felix.engelmanncreate