[Python-ideas] Python Numbers as Human Concept Decimal System

Oscar Benjamin oscar.j.benjamin at gmail.com
Sat Mar 8 19:11:54 CET 2014


On 8 March 2014 16:54, Guido van Rossum <guido at python.org> 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 <dickinsm at gmail.com> wrote:
>>
>> On Sat, Mar 8, 2014 at 9:43 AM, Mark Dickinson <dickinsm at gmail.com> wrote:
>>>
>>>
>>> I see three sane options for float to Decimal conversion:
>>>
>>> 1. Raise an exception.
>>> 2. Round to the nearest Decimal value using the current context for that
>>> round operation.
>>> 3. Do what we're currently doing, and do an exact 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.


Oscar


More information about the Python-ideas mailing list