Skip to content


Comparing floating-point and decimal in Python

Bizarre happenings in the world of Python. It seems that you are really not supposed to compare floating-point and decimal numbers, as this example shows:

Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from decimal import Decimal
>>> Decimal('1.0') > 2.0
False
>>> Decimal('3.0') > 2.0
False
>>> Decimal('1.0') < 2.0
True
>>> Decimal('3.0') < 2.0
True
>>> 2.0 < Decimal('1.0')
False
>>> 2.0 < Decimal('3.0')
False
>>> 2.0 > Decimal('1.0')
True
>>> 2.0 > Decimal('3.0')
True

But that’s not the end yet. I have NLTK 0.9.4 installed, and watch how truth is reversed if I simply import the NLTK package:

>>> import nltk
>>> Decimal('1.0') > 2.0
True
>>> Decimal('3.0') > 2.0
True
>>> Decimal('1.0') < 2.0
False
>>> Decimal('3.0') < 2.0
False
>>> 2.0 < Decimal('1.0')
True
>>> 2.0 < Decimal('3.0')
True
>>> 2.0 > Decimal('1.0')
False
>>> 2.0 > Decimal('3.0')
False

I’m filing bugs about this, but I do find this quite entertaining in a ‘oh-my-God-I-always-believed-Python-was-a-well-behaved-language’ sort of way.

Edit: Edward Loper from NLTK gave an explanation why this is the case – it’s not because of NLTK, but because of Python’s internal handling of the comparison operator on floating-point numbers:

Apparently, you're only allowed to use comparison operators to compare Decimal objects to (i) other Decimal objects; (ii) integers; (iii) longs. Here, you're comparing it to a float, which isn't allowed, as evidenced by the following:
>>> Decimal('.1').__cmp__(1)
-1
>>> Decimal('.1').__cmp__(.3)
NotImplemented

Since Decimal's __cmp__ method returns NotImplemented, python falls back on using .3's __cmp__ method. Unfortunately, when you compare a float to some random object, the results are pretty much arbitrary, and are not guaranteed to be consistent. [...]

nltk's not really playing much of a role here (other than tweaking the system to change that arbitrary result -- my guess would be that the result depends on the pointer address of the Decimal class, or of some other object like that).

Crazy stuff.