[Python-Dev] Signalling NANs

Steven D'Aprano steve at pearwood.info
Fri Nov 9 06:05:07 EST 2018

I'm trying to understand some unexpected behaviour with float NANs in 
Python 3.5.

Background: in IEEE-754 maths, NANs (Not A Number) come in two flavours, 
so called "quiet NANs" and "signalling NANs". By default, arithmetic 
operations on qnans return a qnan; operations on snans "signal", which 
in Python terms means raising an exception.

The original IEEE-754 standard didn't specify how to distinguish a qnan 
from a snan, but a de facto standard arose that bit 51 of the float was 
the "quiet bit", if it were set, the NAN was quiet.

For the purposes of this email, I'm going to assume that standard is in 
place, even though technically speaking it is platform-dependent.

According to my tests, it seems that we cannot create snans in Python. 
The float constructor doesn't recognise "snan", raising ValueError. Nor 
can we convert a Decimal snan into a float:

py> from decimal import Decimal
py> snan = Decimal('snan')
py> float(dsnan)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: cannot convert signaling NaN to float

But unexpectedly (to me at least), we apparently cannot even create a 
signalling NAN by casting 64 bits to a float. Here are the functions I 
use to do the cast:

from struct import pack, unpack

def cast_float2int(x):
    return unpack('<Q', pack('<d', x))[0]

def cast_int2float(i):
    return unpack('<d', pack('<Q', i))[0]

Here's a regular quiet NAN round-tripping, as expected:

py> x = cast_int2float(0x7ff8000000000001)
py> x
py> hex(cast_float2int(x))

So far so good. But now let me try with a signalling NAN:

py> x = cast_int2float(0x7ff0000000000001)
py> x
py> hex(cast_float2int(x))

So it seems that the "quiet" bit is automatically set, even when using 
the struct module, making it impossible to create snan floats.

Is this intended? If so, why?

Is this meant as a language feature?

Thanks in advance,


More information about the Python-Dev mailing list