This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: math.nan should note that NANs do not compare equal to anything
Type: enhancement Stage: resolved
Components: Documentation Versions: Python 3.11, Python 3.10, Python 3.9, Python 3.8, Python 3.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: CharlieZhao, JelleZijlstra, docs@python, miss-islington, serhiy.storchaka, slateny, steven.daprano, veky
Priority: normal Keywords: easy, patch

Created on 2022-03-15 22:47 by steven.daprano, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 32170 merged CharlieZhao, 2022-03-29 02:05
PR 32263 merged miss-islington, 2022-04-02 19:58
PR 32264 merged miss-islington, 2022-04-02 19:58
Messages (13)
msg415302 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2022-03-15 22:47
The IEEE-754 requirement that NANs are never equal to anything, even to themselves, is a common stumbling block for those new to the consequences of IEEE-754. See for example #47020.

The documentation for math.nan would be a good place to add a note like

"Due to the requirements of the `IEEE-754 standard <https://en.wikipedia.org/wiki/IEEE_754>`_, math.nan and float('nan') are never equal to any other value, including themselves. Use math.isnan to test for NANs."

https://docs.python.org/3.8/library/math.html#math.nan
msg415533 - (view) Author: Stanley (slateny) * Date: 2022-03-19 03:26
How does this sound instead? The unequalness is pushed to the front and the IEEE part back so it's less likely missed:

Math.nan and float('nan') are never equal to any other value, including themselves, as per IEEE 754. Use math.isnan to test for NANs.
msg415536 - (view) Author: Vedran Čačić (veky) * Date: 2022-03-19 06:02
I'm not satisfied with "and" formulation. For all practical purposes, math.nan is the "same" object as float('nan'), they just represent two ways of referring to it (or constructing it). To me it sounds a bit like "2 and 1+1 are the only even prime numbers." I suggest the docs only speak of math.nan here, and elsewhere to say that they can also be constructed by float('nan').
msg415537 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2022-03-19 09:22
We cannot guarantee that NAN never equal to anything, because we can create an object equal to it. For example mock.ANY.
msg415639 - (view) Author: Stanley (slateny) * Date: 2022-03-20 22:30
Vedran's got a good point, as existing documentation for math.nan already says

"... Equivalent to the output of float('nan')."

so it does seem a bit redundant to say both, though I wonder if we should still be explicit since

>>> import math
>>> math.nan is math.nan
True
>>> float('nan') is float('nan')
False

so they don't have the exact same behavior.

Serhiy also has a good point, so maybe instead say that Math.nan/float('nan') is *generally* not equal to any other value?
msg415929 - (view) Author: Charlie Zhao (CharlieZhao) * Date: 2022-03-24 09:02
> "Due to the requirements of the `IEEE-754 standard <https://en.wikipedia.org/wiki/IEEE_754>`_, math.nan and float('nan') are never equal to any other value, including themselves. Use math.isnan to test for NANs."

It seems to me, Steven's description is clear enough to tell us that "Be careful if you want to compare NANs with others". 

One thing to emphasize is that neither `is` nor `==` is a best practice, just like slateny's example, we should be wary of the difference between `float('nan')` and `math.nan`.

Adding an example to the docs would be a good way to let everyone know the difference and use `math.isnan` instead of `is` and `==` to test for NANs.
msg415934 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2022-03-24 10:42
> We cannot guarantee that NAN never equal to anything, because we can 
> create an object equal to it. For example mock.ANY

Sure. I don't expect that mock.ANY or other weird objects should obey 
the IEEE-754 rules. But we're talking numeric comparisons here, not 
arbitrary objects which may do arbitrary things in their `__eq__` 
method.

The documentation for the math module assumes we're talking about 
sensible, standard numeric values that don't play strange tricks on the 
caller. Look at the first function documented:

math.ceil(x)
Return the ceiling of x, the smallest integer greater than or equal to 
x. If x is not a float, delegates to x.__ceil__(), which should return 
an Integral value.

    class MyWeirdFloat(float):
        def __ceil__(self):
            return -1

    math.ceil(MyWeirdFloat(25.9))  # Returns -1 instead of the ceiling.

Does the documentation really need to cover every imaginable weird 
class? I don't think so. Let's keep it simple. NANs compared unequal 
with all numeric values which directly or indirectly obey IEEE-754, 
which includes floats.
msg415987 - (view) Author: Stanley (slateny) * Date: 2022-03-25 04:10
Then perhaps saying that it's *never* equal is too strong, and instead we just say it's *not* equal. Not too sure how to phrase the behavior difference between `==` and `is` though, if that's something that should be noted.
msg416246 - (view) Author: Charlie Zhao (CharlieZhao) * Date: 2022-03-29 08:08
I started a PR and some simple examples were added. It is helpful for those who are new to IEEE-754.

According to Jelle's comments, the behavior of `float('nan') is float('nan')` may be changed in the future, so I just omit it and suggest users to use `math.isnan()`. This might make the documentation a bit clearer.
msg416583 - (view) Author: Jelle Zijlstra (JelleZijlstra) * (Python committer) Date: 2022-04-02 19:58
New changeset 182e93c3f57b0c72e765c9896066d32e461c0865 by Charlie Zhao in branch 'main':
bpo-47031: Improve documentation for `math.nan` (GH-32170)
https://github.com/python/cpython/commit/182e93c3f57b0c72e765c9896066d32e461c0865
msg416585 - (view) Author: miss-islington (miss-islington) Date: 2022-04-02 20:19
New changeset 319a70cf99c9866c7fa47deecf04f6ebcfe35a54 by Miss Islington (bot) in branch '3.10':
bpo-47031: Improve documentation for `math.nan` (GH-32170)
https://github.com/python/cpython/commit/319a70cf99c9866c7fa47deecf04f6ebcfe35a54
msg416586 - (view) Author: miss-islington (miss-islington) Date: 2022-04-02 20:23
New changeset 5b80031fb0d2ea14f0d42a33309ce5464c4a6042 by Miss Islington (bot) in branch '3.9':
bpo-47031: Improve documentation for `math.nan` (GH-32170)
https://github.com/python/cpython/commit/5b80031fb0d2ea14f0d42a33309ce5464c4a6042
msg416609 - (view) Author: Jelle Zijlstra (JelleZijlstra) * (Python committer) Date: 2022-04-03 02:35
Thanks for the bug report and patch!
History
Date User Action Args
2022-04-11 14:59:57adminsetgithub: 91187
2022-04-03 02:35:48JelleZijlstrasetstatus: open -> closed
resolution: fixed
messages: + msg416609

stage: patch review -> resolved
2022-04-02 20:23:29miss-islingtonsetmessages: + msg416586
2022-04-02 20:19:23miss-islingtonsetmessages: + msg416585
2022-04-02 19:58:19miss-islingtonsetpull_requests: + pull_request30329
2022-04-02 19:58:13miss-islingtonsetnosy: + miss-islington
pull_requests: + pull_request30328
2022-04-02 19:58:07JelleZijlstrasetnosy: + JelleZijlstra
messages: + msg416583
2022-03-29 08:08:25CharlieZhaosetmessages: + msg416246
2022-03-29 02:05:07CharlieZhaosetkeywords: + patch
stage: patch review
pull_requests: + pull_request30248
2022-03-25 04:10:28slatenysetmessages: + msg415987
2022-03-24 10:42:44steven.dapranosetmessages: + msg415934
2022-03-24 09:02:19CharlieZhaosetnosy: + CharlieZhao
messages: + msg415929
2022-03-20 22:30:52slatenysetmessages: + msg415639
2022-03-19 09:22:00serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg415537
2022-03-19 06:02:11vekysetnosy: + veky
messages: + msg415536
2022-03-19 03:26:02slatenysetnosy: + slateny
messages: + msg415533
2022-03-15 22:47:25steven.dapranocreate