NaN comparisons - Call For Anecdotes

Chris Angelico rosuav at gmail.com
Tue Jul 8 20:42:18 CEST 2014


On Wed, Jul 9, 2014 at 4:29 AM, Anders J. Munch <2014 at jmunch.dk> wrote:
> Chris Angelico wrote:
>> For hash keys, float object identity will successfully look them up:
>
>
> Except you can't expect to rely on object identity in most interesting
> cases.
>
>>>> x = float('nan')
>>>> import struct
>>>> y = struct.unpack('<f', struct.pack('<f', x))[0]
>>>> d[x] = "found"
>>>> d[y]
>
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> KeyError: nan
>
> and also:
>
>>>> def f(): return float('inf')/float('inf')
>>>> f() == f()
> False
>>>> f() is f()
> False

Neither of those examples is anything to do with object identity. In
the first case, you pack the value and recreate an equivalent of the
same type with the same value. In the second, you independently
construct two floats with the same value. Both times, you have
equivalence (both are NaN), but not identical objects.

> Let me conjure up a simple example:
>
> | class Monitor(Thread):
> | def run(self):
> | old = self.get_current_value()
> | while not self.Terminated:
> | new = self.get_current_value()
> | if new != old:
> | print(time.asctime(), "changed to", new)
> | old = new
> | time.sleep(1)
>
> This is a completely generic change detection algorithm, and not a
> "floating-point algorithm" in any way: It will work on strings, lists, sets,
> anything that get_current_value returns, including non-NaN floats. You don't
> need to know anything about floating-point representation to write or use
> such an algorithm, why should you? It works on tuples, sets, lists, serial
> port handles, module objects, pretty much anything you can imagine -- except
> NaN floats.

You also have to cope with objects that define __eq__ or __ne__. If
you know that you have a monitor like that, then you make sure that
the value is something comparable; there are plenty of reasons to have
to be careful there. (Consider, for instance, what happens if
get_current_value() returns a list. Mutating that list can change
whether or not it's equal to something else.)

ChrisA



More information about the Python-list mailing list