Skip to content

Support float's just as int's in decimal.Context methods #125394

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
skirpichev opened this issue Oct 13, 2024 · 7 comments
Closed

Support float's just as int's in decimal.Context methods #125394

skirpichev opened this issue Oct 13, 2024 · 7 comments
Labels
extension-modules C modules in the Modules dir stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@skirpichev
Copy link
Member

skirpichev commented Oct 13, 2024

Feature or enhancement

Proposal:

Right now an exception raised:

>>> ctx = decimal.getcontext()
>>> ctx.ln(1.25)  # (1)
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    ctx.ln(1.25)
    ~~~~~~^^^^^^
TypeError: conversion from float to Decimal is not supported

I believe, that above message is misleading. Actually, conversion is supported:

>>> decimal.Decimal(1.25)
Decimal('1.25')

Note also, that for integer arguments these functions work:

>>> ctx.ln(123)  # (2)
Decimal('4.812184355372417495262008610')

Current workaround is an explicit type cast, e.g.:

>>> ctx.ln(decimal.Decimal(1.25))  # (3)
Decimal('0.2231435513142097557662950903')
>>> decimal.Decimal(1.25).ln()
Decimal('0.2231435513142097557662950903')

But float's could be losslessly converted to Decimal's just as int's. So, probably (1) should behave like (3), without the need for an explicit constructor call, as for int's (2).

If this feature request does make sense, I'll work on a patch.

Has this already been discussed elsewhere?

This is a minor feature, which does not need previous discussion elsewhere

Links to previous discussion of this feature:

No response

@skirpichev skirpichev added the type-feature A feature request or enhancement label Oct 13, 2024
@skirpichev skirpichev self-assigned this Oct 13, 2024
@ronaldoussoren
Copy link
Contributor

I'm not a decimal expert, but the current behaviour seems correct to me. Implicit conversion from float to decimal is not supported in other contexts either, e.g.:

>>> decimal.Decimal(1) + 0.01
Traceback (most recent call last):
  File "<python-input-5>", line 1, in <module>
    decimal.Decimal(1) + 0.01
    ~~~~~~~~~~~~~~~~~~~^~~~~~
TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'

That's because an implicit conversion can result in unexpected behaviour that can be very hard to track down.

@picnixz
Copy link
Member

picnixz commented Oct 13, 2024

While I agree that implicit conversion in arithmetic operations would be inconvenient, I think a direct call should be fine. Or, what we could suggest is an additional context parameter where implicit conversions are allowed, at least for 1-parameter functions. Mixed arithmetic should still reject implicit conversions but we could allow calling 1-parameter functions with inputs that are valid to the Decimal constructor.

(The fact that integers are allowed as inputs to 1-parameter functions is IMO an inconsistency. Either we expect strict decimal instances or we expect inputs that convertible to decimal objects with a simple constructor call).

@picnixz picnixz added stdlib Python modules in the Lib dir extension-modules C modules in the Modules dir labels Oct 13, 2024
@skirpichev
Copy link
Member Author

decimal.Decimal(1) + 0.01

Here (as well as for 2-arg functions on the Context, like add) is some ambiguity, which can't be resolved in a satisfactory way. See #87768 and #46023.

We could deny such implicit conversions in 1-arg methods for consistency with 2-arg methods, but isn't this a foolish consistency?

@serhiy-storchaka
Copy link
Member

More strict type control is to catch errors. Python is dynamically typed but not strongly typed programming language. Implicit lossy conversions are usually prohibited. This is not a matter of convenience, this is a matter of error proofing.

Consider the case when some value is erroneously float instead of Decimal. Now you will get an error, but implicit conversion to Decimal would silently produce imprecise result. Calculation with known precision is the main point of Decimal.

Conversion from int to Decimal is precise, so implicit conversion is allowed.

@skirpichev
Copy link
Member Author

Conversion from int to Decimal is precise

But conversion from float to Decimal is precise as well. Then, for converted (exactly!) value - you can apply context settings and evaluate, say, ln().

@serhiy-storchaka
Copy link
Member

The original value, a float, is already imprecise if you expected Decimal but got float. The bug is in the previous computations.

@skirpichev skirpichev removed their assignment Oct 14, 2024
@skirpichev skirpichev closed this as not planned Won't fix, can't repro, duplicate, stale Oct 14, 2024
@skirpichev
Copy link
Member Author

We also can trap the signal FloatOperation to enable more strict semantics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension-modules C modules in the Modules dir stdlib Python modules in the Lib dir type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants