[Python-ideas] math.inf and math.nan constants
steve at pearwood.info
Sat Jan 10 09:33:05 CET 2015
On Fri, Jan 09, 2015 at 05:38:14AM +0000, Andrew Barnert wrote:
> On Wednesday, January 7, 2015 8:10 AM, Steven D'Aprano <steve at pearwood.info> wrote:
> > Python today doesn't give us any simple way to access all those
> > different float NANs, or offer any interpretation of what they might
> > mean, but it might some day. I am strongly opposed to anything which
> > might pre-empt that or discourage future advances.
> I don't think there's really an issue here; the only thing this
> preempts is using the plain name `float.nan` for such future advances.
Okay, okay, I admit defeat :-)
I must say, compared to some years ago when the prevailing attitude
about NANs was closer to "if Python supports them at all you're lucky",
I am glad to see better support for NANs. If that means baking in the
idea that there is "a NAN", I can live with that.
> What's wrong with, say, `float.make_nan(payload=30, quiet=False,
> sign=True)`? Given that the former is almost certainly going to be
> used far more often than the latter, the extra characters to type and
> read for the uncommon case don't seem like a serious problem.
> Since you brought up SANE, from what I remember (I tried to dig up the
> Apple Numerics Manual or the semi-public SANE 68k assembly source, but
> I give up…), this is roughly equivalent to what SANE did. There was a
> function to return a NaN with a code from 0-255, with meanings like
> "square root of a negative" or "division by zero" or "invalid NaN
> code"—the last being used if you tried to call it with 0 as the code.
The payloads SANE used (adjusted to Python syntax where appropriate):
Name Payload Example
============= ======= =========
NANSQRT 1 sqrt(-1)
NANADD 2 +INF + (-INF)
NANDIV 4 0/0
NANMUL 8 0*INF
NANREM 9 x % 0
NANASCBIN 17 float("foo")
NANCOMP 20 convert COMP NAN to float
NANZERO 21 create NAN with 0 payload
NANTRIG 33 invalid arg to trig functions
NANINVTRIG 34 asin(2.0)
NANLOG 36 log(-1)
NANPOWER 37 invalid arg to x**y
NANFINAN 38 invalid arg to finance funcs
> If you wanted the all-zeros NaN, that was a separate function.
I don't think there is an all-zeroes NAN for single and double format. I
believe they would be +INF or -INF depending on the sign bit.
There was a 64-bit "comp" data type which had a single NAN value,
perhaps that is what you are thinking of. comp was integer valued, and
had no INFs.
> Meanwhile, if you only care about platforms that use x86/68k-style
> representations for IEEE-754 (unfortunately, pre-2008 the bits weren't
> standardized, so at least MIPS did things differently), `make_nan` is
> pretty easy. Something like:
> def make_nan(payload=0, sign=False, quiet=True):
> payload |= (0x7ff0000000000000 |
> (sign * 0x8000000000000000) |
> (quiet * 0x0008000000000000))
> return struct.unpack('d', struct.pack('Q', payload))
> 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).
More information about the Python-ideas