Issue1979
Created on 2008-01-31 04:46 by mark.dickinson, last changed 2008-02-07 16:08 by mark.dickinson.
|
msg61884 - (view) |
Author: Mark Dickinson (mark.dickinson) |
Date: 2008-01-31 04:46 |
|
For Python 3.0 the decimal module got rich comparisons. Those comparisons have somewhat unconventional
behavior with respect to NaNs, as seen below: <, <= and == comparisons involving NaNs always return False,
while >, >= and != comparisons always return True.
The Decimal specification has nothing helpful to say about comparisons involving NaNs. But reading IEEE-
754r (on which the Decimal specification is closely based), there are two possible options:
(1) have comparisons involving NaNs (except for !=) raise InvalidOperation in the context, and hence give a
Python exception (assuming that InvalidOperation isn't trapped.)
(2) have comparisons involving NaNs always return False (except for !=, which always returns True).
I think either of these is better than the current behavior. (2) seems like the better option, for a couple
of reasons: first, it's the way that Python floats currently work, and second, there might be issues with
list membership testing if equality comparisons involving NaNs raised an exception or returned a NaN.
Since Mike Cowlishaw is intimately involved with both the Decimal specification and the IEEE-754r process, I
thought it might be useful to have his opinion on this; his main recommendation was to have the Decimal
type do the same as the float type.
The attached patch makes <, <=, >, >= and == comparisons involving NaNs always return False, and !=
comparisons always return True. It also renames __cmp__ to _cmp and adds a few tests for the new behavior.
Here's how NaN comparisons currently work:
Python 3.0a2+ (py3k:60470M, Jan 30 2008, 23:11:40)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from decimal import *
>>> n = Decimal("nan")
>>> i = Decimal("inf")
>>> n < n
False
>>> n > n
True
>>> i < n
False
>>> i > n
True
See also issue #1514428.
|
|
msg61885 - (view) |
Author: Raymond Hettinger (rhettinger) |
Date: 2008-01-31 05:22 |
|
ISTM, you're now moving far beyond the spec into territory that isn't
covered by tests or standards. Is this necessary?
|
|
msg61894 - (view) |
Author: Mark Dickinson (mark.dickinson) |
Date: 2008-01-31 10:06 |
|
Yes, I think it's necessary.
Speaking of standards, it's the current behavior which isn't backed by any
standard or rationale other than the historical one involving now-defunct 3-
way comparisons.
The proposed behavior is much closer to that specified by C99 (see sections
7.12.14 and section F.3) and by IEEE 754 and its upcoming revision (see
section 5.11 of the most recent draft, which is linked to from the wikipedia
page for IEEE 754r). Even better from a standards-compliance perspective
would be to have all comparisons except != involving NaNs raise the
InvalidOperation flag.
The current behavior also breaks something fundamental: namely, that x < y
should have the same truth value as y > x. Python even depends on this for
reversing comparison operators, which explains, but in my opinion doesn't
excuse, the following oddity:
>>> 2 < Decimal("NaN")
True
>>> Decimal(2) < Decimal("NaN")
False
|
|
msg61914 - (view) |
Author: Mark Dickinson (mark.dickinson) |
Date: 2008-01-31 17:43 |
|
Here's a patch (richcmp_signal.patch) that gives an alternative way of doing things: all
<, <=, > and >= comparisons involving a NaN raise the InvalidOperation flag (using exactly
the same semantics as those specified for compare_signal). == and != comparisons always
return False and True, respectively, just as they do now.
So the post-patch decimal exactly follows IEEE 754(r) on this. I think it makes good sense
from a user's viewpoint, too: with the default settings, any <, <=, > or >= comparison
involving a NaN raises a Python exception; this seems like the best outcome for a beginning
Decimal user, while expert users can choose to use the public compare or compare_signal
methods instead.
My worries about list membership testing were nonsensical: there's only one reasonable
behaviour for == and !=, namely the current behavior, which also matches all the standards.
On balance, I think I prefer this approach to the idea of returning False on comparisons
involving NaNs. The only fly in the ointment is that floats and Decimals behave
differently in this respect.
|
|
msg62110 - (view) |
Author: Facundo Batista (facundobatista) |
Date: 2008-02-06 18:04 |
|
I'm +0 regarding this.
If this will go in, a comment should explicit all this in the code, as
this behaviour doesn't come from Decimal spec or the PEP.
Thanks!
|
|
msg62126 - (view) |
Author: Mark Dickinson (mark.dickinson) |
Date: 2008-02-06 22:13 |
|
Okay: I checked in this change in r60630. The checkin includes comments
in the code and an extra paragraph describing this behavior in the
documentation.
|
|
msg62141 - (view) |
Author: Facundo Batista (facundobatista) |
Date: 2008-02-07 11:39 |
|
Thanks Mark!
Shall this issue be closed?
|
|
msg62155 - (view) |
Author: Mark Dickinson (mark.dickinson) |
Date: 2008-02-07 16:08 |
|
Closing.
|
|
| Date |
User |
Action |
Args |
| 2008-02-07 16:08:14 | mark.dickinson | set | status: open -> closed resolution: fixed messages:
+ msg62155 |
| 2008-02-07 11:39:46 | facundobatista | set | messages:
+ msg62141 |
| 2008-02-06 22:13:30 | mark.dickinson | set | messages:
+ msg62126 |
| 2008-02-06 18:04:11 | facundobatista | set | messages:
+ msg62110 |
| 2008-01-31 17:43:26 | mark.dickinson | set | files:
+ richcmp_signal.patch messages:
+ msg61914 |
| 2008-01-31 13:34:08 | christian.heimes | set | priority: normal nosy:
+ christian.heimes |
| 2008-01-31 10:06:07 | mark.dickinson | set | messages:
+ msg61894 |
| 2008-01-31 05:22:38 | rhettinger | set | nosy:
+ rhettinger messages:
+ msg61885 |
| 2008-01-31 04:46:16 | mark.dickinson | create | |
|