-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
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 to receive from_float method #49046
Comments
In the PEP for Decimal, it was discussed that the class should have a Following discussions with Mark Dickinson, I would like to request The suggested API is: At the risk of derailing the request, I wonder whether it is better to Pro: better control over conversion, as you can specify rounding Con: more difficult for newbies to understand. Semi-pro: float to decimal conversions are inherently tricky, perhaps |
The decimal constructor should be lossless. The underlying spec was To support the use case of wanting to round the input, I suggest a |
FYI, there is already a lossless implementation in the docs: def float_to_decimal(f):
"Convert a floating point number to a Decimal with no loss of
information"
n, d = f.as_integer_ratio()
with localcontext() as ctx:
ctx.traps[Inexact] = True
while True:
try:
return Decimal(n) / Decimal(d)
except Inexact:
ctx.prec += 1 |
I agree with this. Since lossless conversion is feasible, this seems It's lucky that the exponent range for (binary) floats is relatively The recipe in the docs is not industrial strength: it doesn't handle |
One also has to worry about the exponent of the converted result: e.g., IEEE 754 isn't much help here: as far as I can tell it says nothing about I see two reasonable strategies: (1) always use the largest exponent Option (2) is pretty much what the recipe in the docs does already, I |
Mark suggested the following strategy for Decimal.from_float: "always Just for the avoidance of all doubt, do you mean the largest exponent |
Raymond:
-0 on this one. It's going to confuse an awful lot of newbies when Also, why not just extend the Decimal() constructor to accept a float
+1 on this. |
No. I'm using 'exponent' in the sense described in the standard. See: http://speleotrove.com/decimal/dbover.html Equivalently, it's the value of the _exp attribute for a Decimal Briefly, every finite Decimal can be thought of as a triple (sign,
All these have exponent 1: >>> Decimal('1e1')._exp
1
>>> Decimal('0.1e2')._exp
1
>>> Decimal('0.01e3')._exp
1 IOW, leading zeros have no significance; only trailing zeros do.
This was discussed extensively when the decimal module was being |
Mark wrote:
I'm very aware of that. The Decimal PEP says the consensus was for It looks like you and Raymond have rejected #2 but are keeping #1, and Anyway, I'm happy enough so long as Raymond's suggested |
I'm not against #2, but I'm not particularly for it either. In any case, I am -1.100000000000000088817841970012523233890533447265625 on any |
Agree with Mark on how to control rounding. The DecimalWay(tm) is that Also agree with Mark regarding Decimal.from_float() which needs to be The DecimalWay(tm) is to have Decimal constructors be exact and to use I'll submit a patch to this effect (unless someone beats me to it). |
See attached patch for Py27. |
Instead of the repeated divisions and Inexact tests, how about a direct sign = 0 if copysign(1.0, self) == 1.0 else 1
n, d = abs(self).as_integer_ratio()
k = d.bit_length() - 1
return _dec_from_triple(sign, str(n*5**k), -k) should work, and would likely be faster too. I also think the sign of 0 should be preserved: i.e., >>> Decimal.from_float(-0.0)
Decimal('-0') Am still reviewing---more comments to come. |
A couple more things:
return d._fix(self) instead of return self.plus(d) in create_decimal_from_float. The plus method does two things: rounds (It's always been a source of mild irritation to me that there's no |
The direct method is *much* faster! |
Raymond, Do you think it would be worth replacing the two uses of Alex Goretoy pointed out (on c.l.p) that the trunk version of Of course, from_float still won't work with earlier versions |
Yes, please.
Right. I don't see an easy way around that short of having |
Raymond, Mark, thanks for this work! I'd include the following in the PEP (under the "from float" """ It has the following syntax:: Decimal.from_float(floatNumber) where >>> Decimal.from_float(1.1)
Decimal('1.100000000000000088817841970012523233890533447265625')
""" |
I agree the PEP should be updated. Your proposed update looks good to me. |
Go ahead with the update, but it isn't really necessary. The PEPs are |
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: