Skip to content

Document the behaviour of Decimal.__round__ #101575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mdickinson opened this issue Feb 5, 2023 · 7 comments
Closed

Document the behaviour of Decimal.__round__ #101575

mdickinson opened this issue Feb 5, 2023 · 7 comments
Labels
docs Documentation in the Doc dir

Comments

@mdickinson
Copy link
Member

mdickinson commented Feb 5, 2023

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

@mdickinson mdickinson added the docs Documentation in the Doc dir label Feb 5, 2023
@mdickinson
Copy link
Member Author

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'>]

@picnixz
Copy link
Member

picnixz commented Feb 5, 2023

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

@OTheDev
Copy link
Contributor

OTheDev commented Feb 8, 2023

@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?

@mdickinson
Copy link
Member Author

@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__

@newbie-02
Copy link

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.

@serhiy-storchaka
Copy link
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().

miss-islington pushed a commit to miss-islington/cpython that referenced this issue Jun 12, 2024
(cherry picked from commit 7dd8c37)

Co-authored-by: Owain Davies <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Jun 12, 2024
(cherry picked from commit 7dd8c37)

Co-authored-by: Owain Davies <[email protected]>
encukou pushed a commit that referenced this issue Jun 13, 2024
gh-101575: document Decimal.__round__() (GH-101737)
(cherry picked from commit 7dd8c37)

Co-authored-by: Owain Davies <[email protected]>
encukou pushed a commit that referenced this issue Jun 13, 2024
gh-101575: document Decimal.__round__() (GH-101737)
(cherry picked from commit 7dd8c37)

Co-authored-by: Owain Davies <[email protected]>
@encukou encukou closed this as completed Jun 13, 2024
@encukou
Copy link
Member

encukou commented Jun 13, 2024

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.

mrahtz pushed a commit to mrahtz/cpython that referenced this issue Jun 30, 2024
noahbkim pushed a commit to hudson-trading/cpython that referenced this issue Jul 11, 2024
estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation in the Doc dir
Projects
None yet
Development

No branches or pull requests

6 participants