Skip to content

Document the behaviour of Decimal.__round__ #101575

Closed

Description

@mdickinson

Documentation

The documentation is missing a description of the behaviour of round on Decimal objects. It's worth documenting, since the behaviour (particularly with respect to the context) is non-obvious.

Of particular note:

  • two-argument round respects the rounding mode from the Decimal context.
  • single-argument round always does round-ties-to-even, ignoring information from the context
Python 3.12.0a4 (main, Jan 20 2023, 16:04:05) [Clang 13.1.6 (clang-1316.0.21.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from decimal import Decimal, getcontext, ROUND_DOWN
>>> getcontext().rounding = ROUND_DOWN
>>> round(Decimal('3.7'))  # round-ties-to-even; context rounding ignored
4
>>> round(Decimal('3.7'), 0)  # uses the context rounding
Decimal('3')

Linked PRs

Activity

  1. mdickinson commented on Feb 5, 2023

    @mdickinson
    MemberAuthor

    The effect of the current context precision is also worth noting:

    >>> round(Decimal(1.1), 27)
    Decimal('1.100000000000000088817841970')
    >>> round(Decimal(1.1), 28)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
  2. picnixz commented on Feb 5, 2023

    @picnixz
    Member

    I agree that this should be documented, although it is hinted in the pure Python implementation but not in the online documentation:

    If only one argument is supplied, round a finite Decimal
    instance self to the nearest integer [...]. 1

    If a second argument n is supplied, self is rounded to n
    decimal places using the rounding mode for the current
    context. 2

    Footnotes

    1. https://github.com/python/cpython/blob/cf89c16486a4cc297413e17d32082ec4f389d725/Lib/_pydecimal.py#L1843 ↩

    2. https://github.com/python/cpython/blob/cf89c16486a4cc297413e17d32082ec4f389d725/Lib/_pydecimal.py#L1868 ↩

  3. OTheDev commented on Feb 8, 2023

    @OTheDev
    Contributor

    @mdickinson Where do you think it should be documented? Create a new entry for the __round__() method in the Decimal class documentation or write a note under the documentation for the round() builtin?

  4. mdickinson commented on Feb 8, 2023

    @mdickinson
    MemberAuthor

    @OTheDev I was thinking of the decimal module documentation, under Decimal.__round__. That's the approach that the fractions module has taken for the various dunders. E.g., https://docs.python.org/3/library/fractions.html#fractions.Fraction.__round__

  5. newbie-02 commented on Oct 15, 2023

    @newbie-02

    May I suggest first adjusting the behavior and then cementing it in the documentation? A different behavior for ~round() versus ~round(0) or round(Decimal(x),) vs. round(Decimal(x),0) or more generally having a 'context' steering something and sometimes ignoring it is trapping on a high level. Math and computers are complex enough, users need clear and consistent functionalities as good as possible.
    I am aware that this is a problem for backwards compatibility, but also aware that backwards compatibility is a funbrake for progress.
    ( In other words: mankind brain isn't wide enough to store actual programming documentation, checking documentation for each line of code is much too slow, thus users use programs and programmers use languages first and check the docs after failure ... a little late. )
    I see some more inconsistency:
    normally rounding shouldn't change type, but round(Decimal(x)) returns int ( users who want that should use int( Decimal ... ) )
    I am! aware that similar applies to round( float ), but consider that the same problem, a function silently performing a type conversion not requested by the user.

  6. serhiy-storchaka commented on Jan 16, 2024

    @serhiy-storchaka
    Member

    Users are not expected to use __round__() directly. They are expected to use round(). While in other places some dunder methods may be directly documented, I think that it is a bad practice. Instead we should document what operations are supported by the class. For example, instead of adding entries for __enter__() and __exit__() method, say that it can be used as a context manager and describe semantic, instead of adding an entry for __iter__() method, say that it is iterable and produces something.

    In addition to round(), Decimal supports also math.ceil(), math.floor(), math.trunc(), pow(), abs(), divmod(). None of this is documented here.

    Index entries for both round() and Decimal.__round__() should refer to the description of Decimal support of round().

  7. added a commit that references this issue on Jun 12, 2024
  8. added 2 commits that reference this issue on Jun 12, 2024
  9. added 2 commits that reference this issue on Jun 13, 2024
  10. encukou commented on Jun 13, 2024

    @encukou
    Member

    Thanks @OTheDev for the PR. As merged, it documents round(Decimal(...)).
    Before the PR, I didn't know that round uses the context rounding mode only if it gets an argument :)

    PRs to document support of the other functions are welcome, but as far as I know they don't have similarly “interesting” behaviour.

  11. added a commit that references this issue on Jun 30, 2024
  12. added a commit that references this issue on Jul 11, 2024
  13. added a commit that references this issue on Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsDocumentation in the Doc dir

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions