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))
def cast_int2float(i): return unpack('<d', pack('<Q', i))
Here's a regular quiet NAN round-tripping, as expected:
py> x = cast_int2float(0x7ff8000000000001) py> x nan py> hex(cast_float2int(x)) '0x7ff8000000000001'
So far so good. But now let me try with a signalling NAN:
py> x = cast_int2float(0x7ff0000000000001) py> x nan py> hex(cast_float2int(x)) '0x7ff8000000000001'
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,