[Python-Dev] Mixing float and Decimal -- thread reboot

Guido van Rossum guido at python.org
Sun Mar 21 17:53:14 CET 2010


On Sat, Mar 20, 2010 at 6:54 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Guido van Rossum wrote:
>> I think we should seriously reconsider allowing mixed arithmetic
>> involving Decimal, not just mixed comparisons.
>
> I'm glad I'm not the only one that started wondering that. I
> wasn't quite game enough to actually suggest it though :)
>
>> There is one choice which I'm not sure about. Should a mixed
>> float/Decimal operation return a float or a Decimal? I note that
>> Fraction (which *is* properly embedded in the numeric tower) supports
>>  this and returns a float result in this case. While I earlier
>> proposed to return the most "complicated" type of the two, i.e.
>> Decimal, I now think it may also make sense to return a float, being
>>  the most "fuzzy" type in the numeric tower. This would also make
>> checking for accidental floats easier, since floats now propagate
>> throughout the computation (like NaN) and a simple assertion that the
>>  result is a Decimal instance suffices to check that no floats were
>> implicitly mixed into the computation.
>
> To blend a couple of different ideas from the thread reboot together:
>
> I suggest a 'linearised' numeric tower that looks like:
>
> int -> Decimal -> Fraction -> float -> complex
>
> As Adam stated, this is a pragmatic tower stating which implicit
> coercions are defined by the code, not a formal mathematical relationship.
>
> Note that this would involve adding mixed Fraction/Decimal arithmetic as
> well as Decimal/float arithmetic.

Yes, that was my intention too.

> I placed Decimal to the left of
> Fraction to keep Decimal's dependencies clear and because Decimal ->
> Fraction conversions appear straightforward (using power of 10
> denominators) without introducing the precision issues that would arise
> in Decimal -> Fraction conversions.

This is just wrong. Decimal is much more like float than like int or
Fraction, due to its rounding behavior. (You cannot produce exact
results for 1/3 using either Decimal or float.)

Clearly the difficult decision is whether Decimal is between Fraction
and float, or between float and complex (I prefer not to say "to the
left/right of" since PEP 3141 orders the types in the opposite way as
people have been doing here). Both are floating point types that
sometimes produce rounded results (e.g. 1/3); the difference is that
they use different bases and that Decimal has configurable precision
when rounding.

I would make float the last station before complex, whereas Mark would
prefer Decimal to go there. I defer to Mark, who has thought a lot
more about Decimal than I have.

> I also like the idea of adding the decimal context signal that Facundo
> suggests (e.g. under the name ImplicitCoercionToBinaryFloat).

Yes, this is what I was trying to say (but didn't find the right words for).

> So "quick and dirty don't need a perfect answer" operations end up with
> ordinary binary floats, while more precise code can enable the signal
> trap to ensure the calculation fails noisily if binary floats are
> introduced.

But does this break a tie for the relative ordering of Decimal and
float in the tower?

> Allowing implicit operations would also finally allow Decimal to be
> registered with numbers.Real.

Right, that's one aspect of what I meant by "embedded in the numeric tower".

> Whatever we decide to do will need to be codified in a PEP though.
> "Cleaning Up Python's Numeric Tower" or something along those lines.

The cleanup is really just specific to Decimal -- int, Fraction and
float are already properly embedded in the tower (PEP 3141 doesn't
advertise Fraction enough, since it predates it). That we may have to
change the __hash__ implementation for the other types is merely a
compromise towards efficiency.

>> The implementation of __hash__ will be complicated, and it may make
>> sense to tweak the hash function of float, Fraction and Decimal to
>> make it easier to ensure that for values that can be represented in
>> either type the hash matches the equality. But this sounds a
>> worthwhile price to pay for proper embedding in the numeric tower.
>
> And Mark appears to already have a good answer to that problem.

Which I still have to review. (Mark, if you're there, could you make a
brief post here on the mathematical definition of the new hash you're
proposing, and why it is both efficient to compute and good (enough)
as a hash function?)

-- 
--Guido van Rossum (python.org/~guido)


More information about the Python-Dev mailing list