-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add inf and nan to math module #67374
Comments
Proposal: math.nan = float('nan')
math.inf = float('inf') Guido's approval: https://mail.python.org/pipermail/python-ideas/2015-January/030775.html Followup question: Do we add a math.neginf, or somesuch, for float('-inf')? Or just use -math.inf? |
I would prefer to only add inf. It looks like float("-inf") and -float("inf") have exactly the same IEEE 754 representation (at least on my x86_64 CPU): >>> struct.pack("d", float("-inf")) == struct.pack("d", -float("inf"))
True |
Sounds good to me.
IMO no: -inf should be fine. |
Indeed: there's only one negative infinity (and only one positive infinity) in IEEE 754 binary64 format. |
Implementation suggestion: if possible, use the _Py_dg_stdnan and _Py_dg_infinity functions from Python/dtoa.c. These are a little safer than the Py_NAN and Py_HUGE_VAL macros, and will give results consistent with the float("inf") and float("nan") constructions. |
Oh, NaN can be signed? >>> struct.pack("d", float("nan"))
b'\x00\x00\x00\x00\x00\x00\xf8\x7f'
>>> struct.pack("d", float("-nan"))
b'\x00\x00\x00\x00\x00\x00\xf8\xff'
>>> struct.pack("d", -float("nan"))
b'\x00\x00\x00\x00\x00\x00\xf8\xff'
>>> struct.pack("d", -float("-nan"))
b'\x00\x00\x00\x00\x00\x00\xf8\x7f' Why does Python return the same representation for positive and negative NaN? >>> float("nan")
nan
>>> float("-nan")
nan |
History, perhaps? In any case, the sign of a NaN isn't useful information in the same way that the sign of an infinity is. The IEEE 754 standard explicitly refuses to attach any meaning to the sign bit of a NaN. And if we were aiming for a full and faithful representation of NaNs, we'd want to output the payload, too (which is just about as meaningless / meaningful as the sign bit). |
There are several different NaNs. >>> x = struct.unpack('d', b'\x00\x00\x00\x00\x00\x00\xf8\x7f')[0]
>>> x
nan
>>> x == x
False
>>> struct.pack('d', x)
b'\x00\x00\x00\x00\x00\x00\xf8\x7f'
>>> x = struct.unpack('d', b'\x00\x00\x00\x00\x00\x00\xf9\x7f')[0]
>>> x
nan
>>> x == x
False
>>> struct.pack('d', x)
b'\x00\x00\x00\x00\x00\x00\xf9\x7f' Interesting, but 0*inf and inf-inf return values with the same representation as float('-nan'), not float('nan'). >>> inf = float("inf")
>>> struct.pack('d', 0*inf)
b'\x00\x00\x00\x00\x00\x00\xf8\xff'
>>> struct.pack('d', inf-inf)
b'\x00\x00\x00\x00\x00\x00\xf8\xff'
>>> struct.pack('d', float('nan'))
b'\x00\x00\x00\x00\x00\x00\xf8\x7f'
>>> struct.pack('d', float('-nan'))
b'\x00\x00\x00\x00\x00\x00\xf8\xff' |
By tweaking the grammar we can have math.-inf. |
Right: that's because Intel's "default" NaN (i.e., the float it produces as a result of any invalid operation) has its sign bit set. |
AAAARRGH! |
Here's a patch. |
Thanks for the review comments. Here's an updated patch taking the review comments into account (and fixing the spelling of PY_NAN, which should have been Py_NAN). |
One more patch, fixing a misplaced period. |
"History, perhaps? In any case, the sign of a NaN isn't useful information in the same way that the sign of an infinity is. The IEEE 754 standard explicitly refuses to attach any meaning to the sign bit of a NaN. And if we were aiming for a full and faithful representation of NaNs, we'd want to output the payload, too (which is just about as meaningless / meaningful as the sign bit)." So I understand that adding a math.neg_nan would be useless. As adding one constant per possible "NaN" value :-) If I recall correctly the IEEE 754 standard, there is not single NaN value, but a range of NaN. "Two kinds of NaN: a quiet NaN (qNaN) and a signaling NaN (sNaN). A NaN may carry a payload that is intended for diagnostic information indicating the source of the NaN. The sign of a NaN has no meaning, but it may be predictable in some circumstances." says Wikipedia. Well, the current definition of math.nan makes sense, it's the same value than float("nan"). Note: On python-ideas, I asked if math.nan and math.inf should be singleton (as it was requested for float("0.0") in issue bpo-4024). The answer is no. |
I have an updated patch taking into account the most recent review comments (for which thanks!), but it's at home; I'll upload it this evening (UTC+00:00). |
New patch, addressing review comments. |
Except of my small suggestion on the doc (see the review), math_inf_nan4.patch looks good to me. |
May be make math.inf and math.nan special objects so that for all x (except inf and nan): x < math.inf |
2015-01-09 8:16 GMT+01:00 Serhiy Storchaka <report@bugs.python.org>:
What do you mean? Implement a subtype of float and override some methods?
It's already the case for int, float and decimal.Decimal.
Comparison to nan always return False. I would be better to raise an error when nan is compared to other numbers (I mean operations like a>b, not a==b), but Python was not designed like that (nor the IEEE 754?). >>> sorted((nan, 1, nan, 2))
[nan, 1, nan, 2] Sorting with NaN is a common issue :-/ See for example: Anyway, changing NaN behaviour is out of the scope of this issue! |
New changeset cf4bf577749c by Mark Dickinson in branch 'default': |
Committed. Thanks for all the helpful review comments! |
Should inf and nan be added to cmath too? It has e and pi and isnan() and isinf()... Also complex(0, math.nan) a value that is printed as "nanj" and complex("nanj") parses and returns such a value, so the point could be made that there should be a constant named complex.nanj. |
Guido van Rossum added the comment:
Since it's a different module and we are talking about more and |
Hmm; probably, yes. I'll open an issue.
Yes, I suppose it could (along with infj, of course). I don't like it much, and I suspect it would get almost no uses. complex(0, inf) and complex(0, nan) seem like good enough spellings. |
Opened issue bpo-23229. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: