On 8 March 2014 16:54, Guido van Rossum email@example.com wrote:
I'll try to respond to Mark Dickinson's second message (and nothing else that happens in the thread since last night), because (a) it concisely summarizes his position and (b) brings up a new strawman.
On Sat, Mar 8, 2014 at 2:01 AM, Mark Dickinson firstname.lastname@example.org wrote: >
On Sat, Mar 8, 2014 at 9:43 AM, Mark Dickinson email@example.com wrote: > >
I see three sane options for float to Decimal conversion:
I think you're writing this entirely from the POV of an expert in floating point. And I'm glad we have experts like you around! I don't consider myself an expert at all, but I do think I have something to bring to the table -- insight the experience of non-expert users.
Standards compliance is important though. Mark is essentially restating something that is repeated hundreds of times throughout various floating point standards documents: a result may be exact or it must be correctly rounded according to the current context (with appropriate flags set and traps fired).
It is not mandated that results requiring more precision than the current context be exact. It is mandated that if a result is to be inexact then the implementation must use a very specific type of inexactness. I don't believe that a standards-compliant decimal module has any wiggle room to invent a new kind of rounding (which I think would be required to achieve what you suggest).
When a non-expert writes Decimal(1.1), each of the three above outcomes surprises. We know that (1) was unpopular, that's why we changed it. We now know that (3) is unpopular at least in some circles (Mark Harrison can't be the only one who doesn't like it). Changing to (2) wouldn't do much to address this, because the default context has way more precision than float, so it still shows a lot of extraneous digits.
Yes, it's trivial to get rid of those extra digits, just use quotes. But if my proposal were adopted, it would be trivial for numerical experts to get the extra digits -- just use from_float(). At this point, my claim is that we're talking essentially about what is the better experience for most users, and while I am not much of a user of Decimal myself, I believe that my proposal has benefits more people and situations than it has downsides.
If you write Decimal(1.1) and are surprised by the result then you have misunderstood something. It may be that you have little understanding of the difference between binary and decimal floating point (but then why are you using Decimal?). Perhaps you don't fully understand the literal->float->Decimal pathway that occurs when the expression is evaluated because you're new to Python or just haven't really thought about it before.
In any case if the result of Decimal(1.1) surprises you then it's because you're expecting it do something that should be done in a different way. Hiding the extra digits does not help a user to understand how to use Decimal.
I actually use this in teaching to demonstrate how binary floating point works. I think it's important when teaching my students for them to understand that the following is a lie:
>>> a = 1.1 >>> a 1.1
The helpful digit-hiding repr is lying to you. There is no float with the value 1.1. I can sort-of demonstrate this with some arithmetic:
>>> 0.1 + 0.11 - 0.11 - 0.1 1.3877787807814457e-17
But that gives the misleading impression that inexact arithmetic is the source of the error. It's important to understand that the error occurs straight away in the literal "1.1". I demonstrate this by showing that
>>> from decimal import Decimal >>> a = 1.1 >>> Decimal(a) Decimal('1.100000000000000088817841970012523233890533447265625')
which also shows the true value stored in the float.
The fact that I use this in teaching is not supposed to serve as an argument for keeping it (I could just as easily use from_float). My point is that showing the digits helps someone to understand what is going on. If a user is converting float to Decimal without knowing what they're doing then the extra digits are a clue that they don't fully understand what's happening and haven't necessarily used the best approach.
There is a good solution to the problem of non-experts wanting to write 1.1 and get the exact value 1.1: decimal literals. With that they can just write 1.1d and not need to learn any more about it. Earlier in this thread you reject that idea saying that you can't teach it to "newbies": ''' Maybe we can add a new literal notation meaning 'decimal'; that would be a relatively straightforward change to the parser (once the new decimal extension module is incorporated), but it would not do much to avoid surprising newbies (certainly you can't go teaching them to always write 3.14d instead of 3.14). However, it would probably help out frequent users of Decimal. (Then again, they might not be using literals that much -- I imagine the source of most such programs is user or file input.) ''' I disagree. If you're at the point of wanting to use the Decimal module then you're at the point where it's reasonable to learn about Decimal literals.
Also I've written code using the decimal module for high precision calculation and it has lots of decimal literals. That is I do (and I see other's doing)
>>> from decimal import Decimal as D >>> d = D('1e-20')
even though this is never used in the decimal documentation. This is the closest you can get to decimal literals right now.