
As per Aahz's suggestion, I'm moving this discussion here, from Python-Dev. (Thanks Aahz!)
Mark Dickinson wrote:
On Thu, Mar 13, 2008 at 4:20 AM, Imri Goldberg <lorgandon@gmail.com mailto:lorgandon@gmail.com> wrote:
My suggestion is to do either of the following: 1. Change floating point == to behave like a valid floating point comparison. That means using precision and some error measure. 2. Change floating point == to raise an exception, with an error string suggesting using precision comparison, or the decimal module.
I don't much like either of these; I think option 1 would cause a lot of confusion and difficulty---it changes a conceptually simple operation into something more complicated.
As for option 2., I'd agree that there are situations where having a warning (not an exception) for floating-point equality (and inequality) tests might be helpful; but that warning should be off by default, or at least easily turned off.
As I said earlier, I'd like static checkers (like Python-Lint) to catch this sort of cases, whatever the decision may be.
Some Fortran compilers have such a (compile-time) warning, I believe. But Fortran's users are much more likely to be writing the sort of code that cares about this.
Since this change is not backwards compatible, I suggest it be added only to Python 3.
It's already too late for Python 3.0.
Still, I believe it is worth discussing.
3. Programmers will still need the regular ==: Maybe, and even then, only for very rare cases. For these, a special function\method might be used, which could be named floating_exact_eq.
I disagree with the 'very rare' here. I've seen, and written, code like:
if a == 0.0: # deal with exceptional case else: b = c/a ...
or similarly, a test (a==b) before doing a division by a-b. That one's kind of dodgy, by the way: a != b doesn't always guarantee that a-b is nonzero, though you're okay if you're on an IEEE 754 platform and a and b are both finite numbers.
While checking against a==0.0 (and other similar conditions) before dividing will indeed protect from outright division by zero, it will enlarge any error you will have in the computation. I guess it would be better to do the same check for 'a is small' for appropriate values of 'small'.
Or what if you wanted to generate random numbers in the open interval (0.0, 1.0). random.random gives you numbers in [0.0, 1.0), so a careful programmer might well write:
while True: x = random.random() if x != 0.0: break
(A less fussy programmer might just say that the chance of getting 0.0 is about 1 in 2**53, so it's never going to happen...)
Other thoughts:
- what should x == x do?
If suggestion no. 1 is accepted, always return True. If no. 2 is accepted, raise an exception. Checking x==x is as meaningful as checking x==y.
- what should
1.0 in set([0.0, 1.0, 2.0])
and
3.0 in set([0.0, 1.0, 2.0])
do?
Actually, one of the reasons I thought about this subject in the first place, was dict lookup for floating point numbers. It seems to me that it's something you just shouldn't do. As for your examples, I believe these two should both raise an exception. This is even worse than normal comparison - here you are checking against the hash of a floating point number. So if you do that in the current implementation, there's a good chance you'll get unexpected results. If you do that given the implementation of suggestion 1, you'll have a hard time make set work.
Mark
Cheers, Imri.
------------------------- Imri Goldberg www.algorithm.co.il/blogs www.imri.co.il ------------------------- Insert Signature Here -------------------------