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
Decimal.from_float works incorrectly for non-binary floats #71162
Comments
Decimal.from_float() works correctly only if the denominator of as_integer_ratio() of argument is the power of two. Example: >>> from decimal import Decimal
>>> class DecimalFloat(float):
... def as_integer_ratio(self):
... return Decimal(str(self)).as_integer_ratio()
... def __abs__(self):
... return self
...
>>> DecimalFloat(1.2).as_integer_ratio()
(6, 5)
>>> Decimal.from_float(DecimalFloat(1.2))
Decimal('1.50') |
True. Though having a subclass of float that overrides as_integer_ratio seems a fairly unlikely use-case. We could add a check for subclasses of float that the denominator is a power of 2 (using the usual trick: a positive integer n is a power of 2 if and only if I doubt it's worth trying to support arbitrary return values from as_integer_ratio. Note that by overriding as_integer_ratio, you're breaking its "contract": the docs say
and you've lost that "exactly equal". I think it's reasonably to get wrong results or an exception in that case. |
It seems to work correctly here for non-binary floats: >>> from _pydecimal import Decimal
>>> Decimal.from_float(Decimal("1.2"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/_pydecimal.py", line 739, in from_float
raise TypeError("argument must be int or float.")
TypeError: argument must be int or float. I think we should not support strange inheritance hierarchies that |
Once I was going to propose to make as_integer_ratio() returning a pair (n, d) with minimal positive d that n/d (as float) is exactly equal to the original float. I think this is legitimate implementation and doesn't contradict the documentation. I see following ways to resolve this issue:
Most of these solutions will automatically fix bpo-26974, so it doesn't need special fix. |
As Mark hinted at, many people would say there is no issue at all. For more information, see e.g.: http://okmij.org/ftp/Computation/Subtyping/ "Alas, LSP when considered from an OOP point of view is undecidable. You cannot count on a compiler for help in pointing out an error. You cannot rely on regression tests either. It's manual work -- you have to see the problem" |
I don't think 4. is an option: for input of exact type float, from_float should continue to produce the exact value of the float, rather than an approximation to that exact value. There's code out there that depends on this behaviour. Options 1 through 3 all seem reasonable to me. |
I vote for ignoring this and calling it not-a-bug. In a way, it is no more interesting than a dict like object defining __hash__ to return a random number. The intention for from_float() is to convert binary floats. It was not meant to be generalized to handle arbitrary fractions. I concur with Mark's comment, "Note that by overriding as_integer_ratio, you're breaking its "contract"". |
Let's close it then. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: