Thanks for your reply! I totally agree with you.
Not long ago, we even improved the documentation to suggest users to use math.isnan()
instead of is
or ==
when they want to check if a number is a NaN.
We may look at this problem from C and Python.
In C, we could get any NaNs from the function nan(const char* arg)
.
NaN in C
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
int main(void) {
double f1 = nan("1");
uint64_t f1n; memcpy(&f1n, &f1, sizeof f1);
printf("nan(\"1\") = %f (%" PRIx64 ")\n", f1, f1n);
double f2 = nan("2");
uint64_t f2n; memcpy(&f2n, &f2, sizeof f2);
printf("nan(\"2\") = %f (%" PRIx64 ")\n", f2, f2n);
double f3 = -nan("");
uint64_t f3n; memcpy(&f3n, &f3, sizeof f3);
printf("-nan(\"\") = %f (%" PRIx64 ")\n", f3, f3n);
double f4 = nan("");
uint64_t f4n; memcpy(&f4n, &f4, sizeof f4);
printf("nan(\"\") = %f (%" PRIx64 ")\n", f4, f4n);
return 0;
}
/**
* Output:
* nan("1") = nan (7ff8000000000001)
* nan("2") = nan (7ff8000000000002)
* -nan("") = -nan (fff8000000000000)
* nan("") = nan (7ff8000000000000)
*/
But in Python, there is no such freedom, we can only get NaN through function float('nan')
, math.nan
or some special operations(such as 0 * float('inf')
). The return value of float('nan')
is a Python object, we should focus on its underlying implementation. I put some code here to illustrate the value of NaN in CPython.
NaN in Python
// float('nan') will call this function to get the value of float object.
double
_Py_parse_inf_or_nan(const char *p, char **endptr)
{
...
else if (case_insensitive_match(s, "nan")) {
s += 3;
retval = negate ? -Py_NAN : Py_NAN;
}
...
return retval;
}
// Py_NAN: Value that evaluates to a quiet Not-a-Number (NaN).
#if !defined(Py_NAN)
# if _Py__has_builtin(__builtin_nan)
// Built-in implementation of the ISO C99 function nan(): quiet NaN.
# define Py_NAN (__builtin_nan(""))
#else
// Use C99 NAN constant: quiet Not-A-Number.
// NAN is a float, Py_NAN is a double: cast to double.
# define Py_NAN ((double)NAN)
# endif
#endif
As we can see, the real value of float('nan')
could be obtained by macro Py_NAN
, a fixed value. So making NaN a singleton in CPython is available.
Maybe there is something incomplete, please correct me.