[ACCEPTED]-python decimal comparison-decimal

Accepted answer
Score: 26

Re 1, it's indeed the behavior we designed 42 -- right or wrong as it may be (sorry if 41 that trips your use case up, but we were 40 trying to be general!).

Specifically, it's 39 long been the case that every Python object 38 could be subject to inequality comparison 37 with every other -- objects of types that 36 aren't really comparable get arbitrarily 35 compared (consistently in a given run, not 34 necessarily across runs); main use case 33 was sorting a heterogeneous list to group 32 elements in it by type.

An exception was 31 introduced for complex numbers only, making 30 them non-comparable to anything -- but that 29 was still many years ago, when we were occasionally 28 cavalier about breaking perfectly good user 27 code. Nowadays we're much stricter about 26 backwards compatibility within a major release 25 (e.g. along the 2.* line, and separately along 24 the 3.* one, though incompatibilities are allowed 23 between 2 and 3 -- indeed that's the whole 22 point of having a 3.* series, letting us fix past 21 design decisions even in incompatible ways).

The 20 arbitrary comparisons turned out to be more 19 trouble than they're worth, causing user 18 confusion; and the grouping by type can 17 now be obtained easily e.g. with a key=lambda x: str(type(x)) argument 16 to sort; so in Python 3 comparisons between 15 objects of different types, unless the objects 14 themselves specifically allow it in the 13 comparison methods, does raise an exception:

>>> decimal.Decimal('2.0') > 1.2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: Decimal() > float()

In 12 other words, in Python 3 this behaves exactly 11 as you think it should; but in Python 2 10 it doesn't (and never will in any Python 9 2.*).

Re 2, you'll be fine -- though, look to 8 gmpy for what I hope is an interesting way to 7 convert doubles to infinite-precision fractions 6 through Farey trees. If the prices you're 5 dealing with are precise to no more than 4 cents, use '%.2f' % x rather than repr(x)!-)

Rather than a 3 subclass of Decimal, I'd use a factory function 2 such as

def to_decimal(float_price):
    return decimal.Decimal('%.2f' % float_price)

since, once produced, the resulting 1 Decimal is a perfectly ordinary one.

Score: 3

The greater-than comparison works because, by 10 default, it works for all objects.

>>> 'abc' > 123
True

Decimal is right 9 merely because it correctly follows the 8 spec. Whether the spec was the correct approach 7 is a separate question. :)

Only the normal 6 caveats when dealing with floats, which 5 briefly summarized are: beware of edge cases 4 such as negative zero, +/-infinity, and 3 NaN, don't test for equality (related to 2 the next point), and count on math being 1 slightly inaccurate.

>>> print (1.1 + 2.2 == 3.3)
False
Score: 1

If it's "right" is a matter of opinion, but 13 the rationale of why there is no automatic 12 conversion exists in the PEP, and that was 11 the decision taken. The caveat basically 10 is that you can't always exactly convert 9 between float and decimal. Therefore the 8 conversion should not be implicit. If you 7 in your application know that you never 6 have enough significant numbers for this 5 to affect you, making classes that allow 4 this implicit behaviour shouldn't be a problem.

Also, one 3 main argument is that real world use cases 2 doesn't exist. It's likely to be simpler 1 if you just use Decimal everywhere.

More Related questions