Comparing float and decimal

Terry Reedy tjreedy at udel.edu
Tue Sep 30 15:07:08 EDT 2008


Mark Dickinson wrote:
> On Sep 30, 9:21 am, Terry Reedy <tjre... at udel.edu> wrote:
>> If no one beats me to it, I will probably file a bug report or two, but
>> I am still thinking about what to say and to suggest.
> 
> I can't see many good options here.  Some possibilities:

Thanks for responding.  Agreeing on a fix would make it more likely to 
happen sooner ;-)

> (0) Do nothing besides documenting the problem
> somewhere (perhaps in a manual section entitled
> 'Infrequently Asked Questions', or
> 'Uncommon Python Pitfalls').  I guess the rule is
> simply that Decimals don't mix well with other
> numeric types besides integers:  if you put both
> floats and Decimals into a set, or compare a
> Decimal with a Fraction, you're asking for
> trouble.  I suppose the obvious place for such
> a note would be in the decimal documentation,
> since non-users of decimal are unlikely to encounter
> these problems.

Documenting the problem properly would mean changing the set 
documentation to change at least the definitions of union (|), issubset 
(<=), issuperset (>=), and symmetric_difference (^) from their current 
math set based definitions to implementation based definitions that 
describe what they actually do instead of what they intend to do.  I do 
not like this option.

> (1) 'Fix' the Decimal type to do numerical comparisons
> with other numeric types correctly, and fix up the
> Decimal hash appropriately.

(1A) All that is needed for fix equality transitivity corruption and the 
consequent set/dictview problems is to correctly compare integral 
values.  For this, Decimal hash seems fine already.  For the int i I 
tried, hash(i) == hash(float(i)) == hash(Decimal(i)) == 
hash(Fraction(i)) == i.

It is fine for transitivity that all fractional decimals are unequal to 
all fractional floats (and all fractions) since there is no integer (or 
fraction) that either is equal to, let alone both.

This is what I would choose unless there is some 'hidden' problem.  But 
it seem to me this should work: when a float and decimal are both 
integral (easy to determine) convert either to an int and use the 
current int-whichever comparison.

> (2) I wonder whether there's a way to make Decimals
> and floats incomparable, so that an (in)equality check
> between them always raises an exception, and any
> attempt to have both Decimals and floats in the same
> set (or as keys in the same dict) also gives an error.
> (Decimals and integers should still be allowed to
> mix happily, of course.) But I can't see how this could
> be done without adversely affecting set performance.

I pretty strongly believe that equality checks should always work (at 
least in Python as delivered) just as boolean checks should (and do).

> Option (1) is certainly technically feasible, but I
> don't like it much: it means adding a whole load
> of code to the Decimal module that benefits few users
> but slows down hash computations for everyone.
> And then any new numeric type that wants to fit in
> with Python's rules had better worry about hashing
> equal to ints, floats, Fractions, complexes, *and*
> Decimals...

I believe (1A) would be much easier both to implement and for new 
numeric types.
> 
> Option (2) appeals to me, but I can't see how to
> implement it.
> 
> So I guess that just leaves updating the docs.
> Other thoughts?

(3) Further isolate decimals by making decimals also unequal to all 
ints.  Like (1A), this would easily fix transitivity breakage, but I 
would consider the result less desirable.

My ranking: 1A > 3 > 0 > 2.  I might put 1 between 1A and 3, but I am 
not sure.

> Mark

Terry Jan Reedy




More information about the Python-list mailing list