C/C++中的NaN常量(字面值)是什么?

155

在C/C++中,是否可以将NaN赋值给doublefloat?就像在JavaScript中使用a = NaN一样。因此,您稍后可以检查变量是否是数字。


这里我展示了不同方式生成的各种NaN的样子:https://dev59.com/rWMl5IYBdhLWcg3wzpjV#55648118 - Ciro Santilli OurBigBook.com
5个回答

216

在C语言中,NAN的声明位于<math.h>头文件中。

而在C++语言中,std::numeric_limits<double>::quiet_NaN()的声明位于<limits>头文件中。

但是,要检查一个值是否为NaN,你不能将其与另一个NaN值进行比较。相反,在C语言中使用<math.h>中的isnan()函数,在C++语言中使用<cmath>中的std::isnan()函数。


29
或者你可以将该数字与其自身进行比较 - 当且仅当 x 为 NaN 时,x == x 的结果为 false - Archie
8
@Archie:我认为这在任何一种语言中都不能保证。 - Mike Seymour
5
据我所知,即使语言标准不支持,只要编译器声称符合IEEE标准,这个程序应该也能正常工作。 - Pixelchemist
52
确实,如果你需要混淆但不需要可移植性的话,这是一个选项。个人而言,我更喜欢不混淆但具有可移植性的选项,所以我不会自己建议使用它。 - Mike Seymour
11
小注释:NAN 是 float 类型,而非 double 类型。链接 - orion elenzil
显示剩余7条评论

33
作为其他人指出的,您正在寻找std::numeric_limits<double>::quiet_NaN(),尽管我必须说我更喜欢cppreference.com文档。特别是因为这个语句有点含糊不清:

只有在std::numeric_limits::has_quiet_NaN == true时才有意义。

如果您查看他们关于std::numeric_limits::has_quiet_NaN的部分,就可以简单地弄清楚这是什么意思:

该常量对所有浮点类型都有意义,并且如果std::numeric_limits::is_iec559 == true,则保证为true。

此处所述,如果true,则表示您的平台支持IEEE 754标准。先前的线程解释了在大多数情况下应该是真实的。


9

这可以使用C++中的numeric_limits来完成:

http://www.cplusplus.com/reference/limits/numeric_limits/

这些是您可能想查看的方法:
infinity()  T   Representation of positive infinity, if available.
quiet_NaN() T   Representation of quiet (non-signaling) "Not-a-Number", if available.
signaling_NaN() T   Representation of signaling "Not-a-Number", if available.

8
维基百科上有一些关于“quiet NaN”(静默NaN)和“signaling NaN”(信号NaN)的信息。 - Drew Noakes

7

在C语言中,可以将NaN赋值给double或float类型的变量吗?

是的,自从C99(C++11)起,<math.h> 提供了以下函数:

#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);

这些内容类似于它们的strtod("NAN(n-char-sequence)",0)对应项和用于赋值的NAN

// Sample C code
uint64_t u64;
double x;
x = nan("0x12345");
memcpy(&u64, &x, sizeof u64); printf("(%" PRIx64 ")\n", u64);
x = -strtod("NAN(6789A)",0);
memcpy(&u64, &x, sizeof u64); printf("(%" PRIx64 ")\n", u64);
x = NAN;
memcpy(&u64, &x, sizeof u64); printf("(%" PRIx64 ")\n", u64);

样例输出:(实现依赖)
(7ff8000000012345)
(fff000000006789a)
(7ff8000000000000)

... 检查变量是否为数字。

使用 <math.h><cmath> 中的 isnan(),std::isnan()


1
不同字符串的输出有什么区别?在典型的数字代码中应该使用哪一个? - quant_dev
2
@quant_dev x = NAN; 可以满足大部分需求,否则 x = nan("0x12345"); 是一种清晰的指定有效负载的方式。有效负载内容的差异是实现定义的。通常,52位有效负载的MSB是一个“quiet”/“signaling”标志。请参见NAN - chux - Reinstate Monica
很棒的例子,非常感谢。我们什么时候应该使用例如 x = nan("0x12345"); 而不是通用的 NAN?我的意思是为什么我们需要说 0x12345 是一个 NaN? - afp_2008
1
@afp_2008 当非数字被实现时,通常会有许多非数字。通常实现了安静和信号NAN。当代码想要返回除默认的NAN之外的其他内容,例如表示安静/信号或某些其他元数据时,可以使用nan("some_numeric_string")。这有点像这个的重新解释。如果您需要更多信息,请提出一个具体的问题?我记得有一个系统标记了地址的低位,以帮助确定NAN的来源。 - chux - Reinstate Monica
@chux-ReinstateMonica,提供的链接无法使用。 - afp_2008
1
@afp_2008 好奇怪,我成功地找到了我之前对 quant_dev 的评论。 - chux - Reinstate Monica

-18

是的,通过指针的概念,您可以像这样为int变量执行操作:

int *a;
int b=0;
a=NULL; // or a=&b; for giving the value of b to a
if(a==NULL) 
  printf("NULL");
else
  printf(*a);

这非常简单和直接。在Arduino IDE中对我有效。


3
“NULL”和“NaN”实际上不是同一个东西。 - Benjamin Zach
1
是的,它们基本上是不同的,但在检查变量是否为数字方面,使用NULL或NaN是相同的。 - Mohammad Reza Abedini
6
“_it worked for me_”与问题无关。问题是如何将NAN赋给floatdouble类型变量。这个回答中没有涉及到NANfloatdouble。请注意保持原意,并尽可能使语言更通俗易懂。 - wovano
使用NULL或NaN在检查变量是否为数字方面是相同的。但是,与NaN进行的许多比较与此不同。 - rsaxvc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接