[issue4087] equality involving Decimals is not transitive; strange set behaviour results

2008-10-09 Thread Mark Dickinson

New submission from Mark Dickinson [EMAIL PROTECTED]:

The Decimal module breaks transitivity of equality:  Decimal(2) == 2 and 
2 == float(2), but Decimal(2) != float(2).

The Python set and dict implementations rely on transitivity of equality 
for correct operation.

These two facts together give some strange results when playing with 
sets and dicts involving Decimals and floats.  For example (with Python 
2.6):

 s = set([Decimal(2), float(2)])
 t = set([2])
 s | t == t | s
False
 len(s | t)
2
 len(t | s)
1

Other strange examples, and possible solutions, were discussed recently 
on comp.lang.python;  see the thread starting at:

http://mail.python.org/pipermail/python-list/2008-September/508859.html

Possible solutions:

(1) Document the problem, making it clear in the language reference that 
correct set operation relies on transitivity of equality, and adding a 
note to the decimal documentation indicating that mixing floats and 
Decimals in a container is asking for trouble.

(2) Fix up Decimal so that equal numeric objects compare equal; this 
would also involve fixing the hash operation.  To me, this goes against 
the philosophy of keeping the Decimal module close to the specification.

(3) Terry Reedy suggested (in the c.l.python thread linked to above) a 
simpler version of (2): allow Decimal(i) == float(i) or Decimal(i) == 
Fraction(i) to return True for all integers i.  (Decimal('0.5') == 0.5 
would still return False.)  This fixes transitivity, and has the 
advantage of not requiring any changes to the hash functions:  
hash(Decimal(i)) == hash(float(i)) is already true for all integers i.

My own preference would be simply to document the problem;  it doesn't 
seem like something that's going to affect that vast majority of Python 
users.

Raymond, Facundo:  any thoughts?

--
messages: 74576
nosy: facundobatista, marketdickinson, rhettinger, tjreedy
priority: normal
severity: normal
status: open
title: equality involving Decimals is not transitive;  strange set behaviour 
results
type: behavior
versions: Python 2.6, Python 2.7, Python 3.0

___
Python tracker [EMAIL PROTECTED]
http://bugs.python.org/issue4087
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue4087] equality involving Decimals is not transitive; strange set behaviour results

2008-10-09 Thread Terry J. Reedy

Terry J. Reedy [EMAIL PROTECTED] added the comment:

There are two issues involved:
1. documenting set behavior
2. what to do, if anything, about Decimals and other numbers

Since users are free to create similar problems, and since sets are
missing from the Reference section on comparisons, I opened a separate
set documentation issue http://bugs.python.org/issue4090
leaving this as a Decimal-other_number equality issue.

The root of the problem is that all members of s are members of t and
vice versa.  This should make s and t equal, but they are not.  This
also breaks the definitions of issubset (=), issuperset (=), union
(|), and symmetric_difference (^) as shown in the c.l.p thread.

Transitivity is also fundamental in logic and the rule of substitution.
 So I strongly prefer that it be preserved in Python as released.

Another way to restore transitivity is
(4) make Decimal(1) != int(1) just as Decimal(1) != float(1).  Having a
Decimal be equal in value to just one of two things that are equal in
value is incoherent, and leads to incoherent results.

___
Python tracker [EMAIL PROTECTED]
http://bugs.python.org/issue4087
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue4087] equality involving Decimals is not transitive; strange set behaviour results

2008-10-09 Thread Facundo Batista

Facundo Batista [EMAIL PROTECTED] added the comment:

(Ok, remember that I'm not a numeric guy before start hitting me, :p )

I think that if we have Decimal(1)==1, and 1==1.0, to have Decimal(1)==1.0.

We always rejected comparison with unsupported types, but having this
situation, I'd propose to put something like the following at the
beggining of __eq__() and similars:

def __eq__(self, other):
if isinstance(other, float) and int(other)==other:
other = int(other)

What do you think?

___
Python tracker [EMAIL PROTECTED]
http://bugs.python.org/issue4087
___
___
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com