[Python-ideas] math.inf and math.nan constants

Andrew Barnert abarnert at yahoo.com
Fri Jan 9 16:32:52 CET 2015

On Jan 9, 2015, at 4:25, Alexander Heger <python at 2sn.net> wrote:

>>    def make_nan(payload=0, sign=False, quiet=True):
>>        payload |= (0x7ff0000000000000 |
>>                    (sign * 0x8000000000000000) |
>>                    (quiet *  0x0008000000000000))
>>        return struct.unpack('d', struct.pack('Q', payload))[0]
>> And likewise, you could write a `parse_nan` that returns `payload, sign, quiet`. And you'd probably want to add some parameter validation (and don't forget that payload 0 and quiet-bit 0 means it's not a NaN, it's an inf).
> so, payload default should not be 0 but, e.g., 1.

I don't think so.

The NaN you get from float("nan") on most platforms is positive, quiet, payload 0 (matching the defaults above). The NaN you get from np.nan is usually either the same, or the negative version of it. Also, any library that defines meanings for NaN payloads is presumably going to define one for 1 (I'm pretty sure SANE did), and it's unlikely to be anything generic. And on platforms where the native C lib displays detailed NaN information, quiet 0 will just be NaN or qNaN or similar, but quiet 1 will be NaN1 or qNaN(1) or similar. So, 1 is not a good default.

Maybe the obvious answer is to not provide a default value at all; if you want quiet 0 you have to make_nan(0), not just make_nan, and that will raise if you happen to be on an old reversed-quiet-bit platform, while if you want default NaN you just use float.nan instead of float.make_nan. You could even to do as SANE did (or at least as I remember it) and not allow 0 at all; if you want quiet 0 you use float.nan. Or, alternatively, make the default None, which uses the right default payload for your platform. 

Speaking of which, IIRC, the default payload on MIPS machines (which had reversed quiet bit) was -1. Which implies that it might be handy to take negative payloads and complement off 1<<51, because if anyone has any use for such payloads they may be thinking of them as negatives, not as huge positives.

But anyway, I think all of this shows why we probably don't want to add make_nan today, but how easily we (or even a third-party lib) can add it later, once someone has a platform/library that they need it for so we can paint the bikeshed to match the house.

And my original point: adding float.nan to 3.5 doesn't prevent a more detailed NaN API in the future.

More information about the Python-ideas mailing list