NANs [was Re: Eval of expr with 'or' and 'and' within]

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Jun 15 00:22:53 EDT 2013


On Sat, 15 Jun 2013 12:03:08 +1000, Cameron Simpson wrote:

> | ... even taking that into account! *wink* |
> | Everyone is aware that there is more than one NAN, right?
> 
> I was not. Interesting.
> 
> | If my
> | calculations are correct, there are 9007199254740992 distinct float
> | NANs in Python (although there is no direct way of distinguishing
> | them).
> 
> Wouldn't id() do it? At least in terms of telling them apart? I gather
> they're not inspectable in Python?

I'm not talking about different *objects*. It would be terribly wasteful 
for Python to pre-allocate 9-gazillion NAN objects. I'm talking about 
distinct values, in the C-double sense.

Python may or may not cache floats in general. In general, it doesn't:

py> x = 2.5
py> y = 2.5
py> x is y
False


but in principle Python might choose to cache some, or all float objects, 
like it does with some ints and strings:

# simulated, not real
py> x = 0.0
py> y = 0.0
py> x is y
True

So you can always distinguish two floats, including NANs, *by value* with 
== and by *object identity* with id() and `is`. But that's not what I'm 
referring to.

The layout of a C double (the numeric value of a float object) is 64 bits:

|s|..e..|......f......|

where s is a single sign bit, e is an 11-bit biased exponent, and f is a 
52-bit binary fraction. If e is 2047 (0b11111111111) then the double is a 
special value, either an INF or a NAN:

e = 2047, f == 0: double is +INF or -INF, depending on s

e = 2047, f != 0: double is a NAN

With a 52-bit f field, there are 4503599627370496 distinct payloads with 
the sign bit set, and another 4503599627370496 with it cleared. Python 
gives you no direct way of testing or setting that payload, or for that 
matter the sign bit, on a NAN, although you can use the struct module to 
cast a float to a 64-bit int and then do bit twiddling. But in principle, 
with 51 (why not 52? see below) bits available, you can stuff quite a 
fair bit of diagnostic information in a NAN, if you need to.

The high bit of f is reserved for a special purpose. If the high bit is 
set (i.e. f >> 51 == 1) the NAN is considered a signalling NAN, which (in 
implementations that comply with the IEEE 754 standard) are guaranteed to 
halt the calculation immediately. Those with it cleared are quiet NANs, 
and are intended to propagate through calculations[1], although that is 
configurable[2].




[1] It's not quite true that once a NAN has entered a calculation, it is 
guaranteed to be the final result. There are circumstances where NANs can 
legitimately disappear from a calculation, leaving an actual number.

[2] Python doesn't allow you to configure float's behaviour but the 
Decimal module does.


-- 
Steven



More information about the Python-list mailing list