msg233580 - (view) |
Author: Ethan Furman (ethan.furman) *  |
Date: 2015-01-07 16:33 |
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?
|
msg233581 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2015-01-07 16:42 |
> 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
|
msg233582 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 16:57 |
Sounds good to me.
> Do we add a math.neginf
IMO no: -inf should be fine.
|
msg233583 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 16:58 |
> float("-inf") and -float("inf") have exactly the same IEEE 754 representation
Indeed: there's only one negative infinity (and only one positive infinity) in IEEE 754 binary64 format.
|
msg233585 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 17:07 |
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.
|
msg233588 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2015-01-07 17:25 |
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
|
msg233591 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 18:18 |
> Why does Python return the same representation for positive and negative 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).
|
msg233593 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2015-01-07 18:25 |
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'
|
msg233594 - (view) |
Author: Antoine Pitrou (pitrou) *  |
Date: 2015-01-07 18:27 |
By tweaking the grammar we can have math.-inf.
|
msg233595 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 18:27 |
> but 0*inf and inf-inf return values with the same representation as float('-nan'), not float('nan')
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.
|
msg233596 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 18:27 |
> By tweaking the grammar we can have math.-inf.
AAAARRGH!
|
msg233598 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 18:42 |
Here's a patch.
|
msg233601 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 19:27 |
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).
|
msg233602 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-07 20:02 |
One more patch, fixing a misplaced period.
|
msg233607 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2015-01-07 22:09 |
"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 #4024). The answer is no.
|
msg233630 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-08 08:58 |
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).
|
msg233674 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-08 17:40 |
New patch, addressing review comments.
|
msg233692 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2015-01-08 22:41 |
Except of my small suggestion on the doc (see the review), math_inf_nan4.patch looks good to me.
|
msg233720 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2015-01-09 07:16 |
May be make math.inf and math.nan special objects so that for all x (except inf and nan):
x < math.inf
x > -math.inf
not (x < math.nan)
not (x > math.nan)
|
msg233737 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2015-01-09 08:57 |
2015-01-09 8:16 GMT+01:00 Serhiy Storchaka <report@bugs.python.org>:
> May be make math.inf and math.nan special objects so that for all x (except inf and nan):
What do you mean? Implement a subtype of float and override some methods?
> x < math.inf
> x > -math.inf
It's already the case for int, float and decimal.Decimal.
> not (x < math.nan)
> not (x > math.nan)
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:
https://stackoverflow.com/questions/4240050/python-sort-function-breaks-in-the-presence-of-nan
Anyway, changing NaN behaviour is out of the scope of this issue!
|
msg233842 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2015-01-11 11:55 |
New changeset cf4bf577749c by Mark Dickinson in branch 'default':
Issue #23185: add math.inf and math.nan constants.
https://hg.python.org/cpython/rev/cf4bf577749c
|
msg233843 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-11 11:56 |
Committed. Thanks for all the helpful review comments!
|
msg233894 - (view) |
Author: Guido van Rossum (gvanrossum) *  |
Date: 2015-01-12 22:41 |
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.
|
msg233912 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2015-01-13 09:07 |
Guido van Rossum added the comment:
> 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.
Since it's a different module and we are talking about more and
different constants, I suggest to open a new issue.
|
msg233917 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-13 09:35 |
> Should inf and nan be added to cmath too?
Hmm; probably, yes. I'll open an issue.
> so the point could be made that there should be a constant named complex.nanj
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.
|
msg233920 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2015-01-13 09:37 |
Opened issue #23229.
|
|
Date |
User |
Action |
Args |
2022-04-11 14:58:11 | admin | set | github: 67374 |
2015-01-13 09:37:33 | mark.dickinson | set | messages:
+ msg233920 |
2015-01-13 09:35:45 | mark.dickinson | set | messages:
+ msg233917 |
2015-01-13 09:07:12 | vstinner | set | messages:
+ msg233912 |
2015-01-12 22:41:31 | gvanrossum | set | nosy:
+ gvanrossum messages:
+ msg233894
|
2015-01-11 11:56:31 | mark.dickinson | set | status: open -> closed resolution: fixed messages:
+ msg233843
stage: needs patch -> resolved |
2015-01-11 11:55:40 | python-dev | set | nosy:
+ python-dev messages:
+ msg233842
|
2015-01-11 00:05:27 | ethan.furman | set | nosy:
+ lemburg, rhettinger, eric.smith, stutzbach
|
2015-01-09 08:57:16 | vstinner | set | messages:
+ msg233737 |
2015-01-09 07:16:11 | serhiy.storchaka | set | messages:
+ msg233720 |
2015-01-08 22:41:09 | vstinner | set | messages:
+ msg233692 |
2015-01-08 17:40:20 | mark.dickinson | set | files:
+ math_inf_nan4.patch
messages:
+ msg233674 |
2015-01-08 08:58:49 | mark.dickinson | set | messages:
+ msg233630 |
2015-01-07 22:09:05 | vstinner | set | messages:
+ msg233607 |
2015-01-07 20:02:37 | mark.dickinson | set | files:
+ math_inf_nan3.patch
messages:
+ msg233602 |
2015-01-07 19:27:27 | mark.dickinson | set | files:
+ math_inf_nan2.patch
messages:
+ msg233601 |
2015-01-07 18:42:47 | mark.dickinson | set | files:
+ math_inf_nan.patch assignee: mark.dickinson messages:
+ msg233598
keywords:
+ patch |
2015-01-07 18:27:45 | mark.dickinson | set | messages:
+ msg233596 |
2015-01-07 18:27:27 | mark.dickinson | set | messages:
+ msg233595 |
2015-01-07 18:27:06 | pitrou | set | nosy:
+ pitrou messages:
+ msg233594
|
2015-01-07 18:25:27 | serhiy.storchaka | set | nosy:
+ serhiy.storchaka messages:
+ msg233593
|
2015-01-07 18:18:08 | mark.dickinson | set | messages:
+ msg233591 |
2015-01-07 17:25:57 | vstinner | set | messages:
+ msg233588 |
2015-01-07 17:07:00 | mark.dickinson | set | messages:
+ msg233585 |
2015-01-07 16:58:50 | mark.dickinson | set | messages:
+ msg233583 |
2015-01-07 16:57:53 | mark.dickinson | set | nosy:
+ mark.dickinson messages:
+ msg233582
|
2015-01-07 16:55:21 | berker.peksag | set | components:
+ Library (Lib) stage: needs patch |
2015-01-07 16:42:15 | vstinner | set | nosy:
+ vstinner messages:
+ msg233581
|
2015-01-07 16:33:44 | ethan.furman | create | |