如何在 c 中产生 NaN 浮点数?

Posted

技术标签:

【中文标题】如何在 c 中产生 NaN 浮点数?【英文标题】:How to produce a NaN float in c? 【发布时间】:2011-11-04 22:57:03 【问题描述】:
float f = (float)'a';
if(f < 0) 
   
else if(f == 0) 
   
else if(f > 0) 
   
else
    printf("NaN\n");                                                          
   

f 不会大于/等于/小于0,如果它是NaN

但是首先如何产生这样的f

我尝试了各种方法来生成NaN,但都没有奏效..

【问题讨论】:

gnu.org/s/hello/manual/libc/Infinity-and-NaN.html 你能用一点 C++ 吗? C++ 有 std::numeric_limits 东西,其中包括安静和信号 NaN 的常量。另外,您确定您的系统正确支持 NaN 吗?因为当你说 0.0/0.0 不是 NaN 时,我真的很惊讶,而且我开始怀疑你的库没有按照你想象的方式设置。 这里我展示了各种 NaN 在通过不同方式生成时的样子:***.com/questions/18118408/… C++ 版本:***.com/questions/16691207/c-c-nan-constant-literal 【参考方案1】:

使用浮点数,0.0 / 0.0 不是“除以零”错误;结果是NaN

这个 C 程序打印 -nan:

#include <stdio.h>

int main()

    float x = 0.0 / 0.0;
    printf("%f\n", x);
    return 0;

NaN 对计算机的外观而言,两个“无效”数字为“信号”和“安静”NaN 保留(类似于为正无穷和负无穷保留的两个无效数字)。 Wikipedia entry 有更多关于如何将 NaN 表示为 IEE 浮点数的详细信息。

【讨论】:

@Je Rog:我的错,我已经修正了我的答案。 @Matt Ball,这是否意味着 IEEE 包含 小于 2^128 个浮点值的定义?只有在这种情况下,才能有一些特殊值用作 NaN IMO @Dan Cecile:我认为除以零会产生一个不确定 (IND) 数,而不是 NaN。 @MNS 整数除以零是未定义的行为。 C中没有“不定数”或“IND”。 @Copperpot 是的,微软编译器的问题是众所周知的。请参阅my answer(我刚刚发布)以获取使用这些编译器(由 GNU MPFR 使用)的解决方案以及针对各种实现的其他解决方案,每次都提到可移植性问题。【参考方案2】:

要产生一个nan,有几种方法:

1) 手动生成(阅读ieee754 以正确设置位)

2) 使用宏。 GCC 公开了一个宏 NAN。它在 math.h 中定义

检查 nan 的一般方法是检查 if (f == f)(对于 nan 值应该会失败)

对于nan来说,float表示中的指数位都应该设置为1(float由一个有符号位、一组指数位和一组尾数位组成)

【讨论】:

您也可以使用 isnan() 检查 NaN(需要 C99 或(在 unix 系统上)适当的功能标志,有关详细信息,请参阅手册页) @bdonlan 有点 OT,但实际上很奇怪,python 直到 2.6 才引入 isnan 我在 bits/nan.h 中为我的工具集找到了 NAN。 对于 (1),存在 IEEE 754 未涵盖的各种可移植性问题(有关详细信息,请参阅 my answer)。关于(2),NAN 不是来自 GCC,而是来自 C 库。例如,参见 GNU libc 的 .../bits/nan.h 文件(如 @DarenW 所述);但是,当通过预处理器测试检测到宏定义时,它是特定于 GCC 的。 "对于 nan,浮点表示中的指数位都应设置为 1" - naninf 都是如此。【参考方案3】:

来自 GNU GCC 手册 math.h 定义了允许您将变量显式设置为无穷大或 NaN 的宏。由于这是 C99 的一部分,我希望您可以将以下宏与其他符合 c99 的编译器一起使用。

— 宏:float INFINITY 表示正无穷大的表达式。它等于 1.0 / 0.0 等数学运算产生的值。 -INFINITY 表示负无穷。

您可以通过将浮点值与此宏进行比较来测试它是否是无限的。但是,不建议这样做;您应该改用 isfinite 宏。请参阅浮点类。

这个宏是在 ISO C99 标准中引入的。

— 宏:float NAN 表示“非数字”值的表达式。此宏是 GNU 扩展,仅在支持“非数字”值的机器上可用,也就是说,在所有支持 IEEE 浮点的机器上可用。

你可以使用‘#ifdef NAN’来测试机器是否支持NaN。 (当然,您必须安排 GNU 扩展可见,例如通过定义 _GNU_SOURCE,然后您必须包含 math.h。)

有关更多信息,您可以在此处查看: http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html

【讨论】:

NAN 宏不是 GNU 扩展(嗯,至少不再是)。它已在 ISO C99 标准中引入。因此,不用定义_GNU_SOURCE,以某种形式的 C99 模式或更高版本(而不是 C89)编译就足够了。【参考方案4】:

这也适用于常量(0/0 会在 vs 上给出编译器错误):

const unsigned maxU = ~0;
const float qNan =  *((float*)&maxU);

【讨论】:

至少有 4 个可移植性问题:~ 在有符号整数类型上、int 可能太短(例如在某些嵌入式系统上)、NaN 表示和损坏的别名规则。有关详细信息,请参阅my answer。【参考方案5】:

下面的 C 程序将产生一个 NaN。第二条语句将产生一个 NaN。

#include <stdio.h>
#include <tchar.h>
#include "math.h"

int _tmain(int argc, _TCHAR* argv[])

    double dSQRTValue = sqrt( -1.00 ); 
    double dResult = -dSQRTValue;  // This statement will result in a NaN.
    printf( "\n %lf", dResult );

    return 0;

以下将是程序的输出。

1.#QNAN0

【讨论】:

【参考方案6】:

您可以使用NAN 宏,或简单地使用nan/nanf 函数之一将nan 值分配给变量。 要检查您是否处理的是 nan 值,可以使用 isnan()。 这是一个例子:

#include <stdio.h>
#include <math.h>

int main(void) 

    float a = NAN;//using the macro in math.h
    float f = nanf("");//using the function version 
    double d = nan("");//same as above but for doubles!

    printf("a = %f\nf = %f\nd = %f\n",a,f,d);

    if(isnan(a))
        puts("a is a not a number!(NAN)\n");

    return 0;

运行上面的代码 sn-p 会给你这个输出:

a = nan
f = nan
d = nan
a is a not a number!(NAN)

自己运行代码:http://ideone.com/WWZBl8 阅读更多信息:http://www.cplusplus.com/reference/cmath/NAN/

【讨论】:

这可能是因为nannanf 不是标准的C 函数。 @skyking nannanf 是自 1999 年以来的标准 ISO C 函数【参考方案7】:

当我们编程包含像@Dan Cecile OR sqrt(-1)所说的0.0/0.0这样的值时,会产生nan。

【讨论】:

【参考方案8】:

对于托管的 C 实现,可以执行 #include &lt;math.h&gt; 并使用 NAN 宏(如果已定义)。例如,对于 GCC,它是由一个内置函数实现的:(__builtin_nanf (""))

对于独立的 C 实现(&lt;math.h&gt; 标头可能不可用)或未定义 NAN 宏时(即使可能支持 NaN 也可能发生),可以生成带有浮动的 NaN点操作如0.0 / 0.0。但是,它可能存在几个问题。

首先,这样的操作也会产生异常,在某些 C 实现中可能存在陷阱。可以确保它是在编译时计算的:

static double my_nan = 0.0 / 0.0;

另一个问题是 Microsoft Visual C++(至少在某些版本)试图在编译时评估 0.0 / 0.0(即使此表达式位于代码中的任意位置)并抱怨其有效性。所以,这里的解决方案是相反的:确保编译器不会在编译时评估它,方法是:

static double zero = 0.0;

然后使用zero / zero。由于这些解决方案存在冲突,因此可以在 specific macros 上使用预处理器指令 (#if...) 测试编译器。

也可以选择基于 NaN 编码的解决方案,但也存在可移植性问题。首先,IEEE 754 标准并没有完全定义 NaN 的编码,特别是区分静默和信令 NaN 的方式(并且硬件在实践中有所不同);信号 NaN 将产生未定义的行为。此外,IEEE 754 标准没有定义位串在内存中的表示方式,即可能需要检测字节顺序。如果这些问题都解决了,带有指针转换的 unsigned char 的联合或数组就可以得到浮点类型。不要使用带有指向地址的指针的整数来进行类型双关,因为这会破坏 C 别名规则。

【讨论】:

【参考方案9】:

-nan也可以通过将一个浮点变量的32位全部设置为1来产生,如下所示:

float nan_val = 0xffffffff;

此外,您可以通过检查与自身的比较是否失败来显式比较浮点变量是否为-nan

if (nan_val != nan_val) 
// executes iff nan_val is -nan

这种比较方法应该适用于使用 IEEE 浮点数的编译器。

【讨论】:

浮点 nan_val = 0xffffffff;只是创建一个值为 4294967296 的浮点数,而不是 -nan。

以上是关于如何在 c 中产生 NaN 浮点数?的主要内容,如果未能解决你的问题,请参考以下文章

当任何数学运算在 .net 4 中产生“NaN”时,如何强制 C# 编译器抛出异常?

浮点数或双精度数的 NaN 和 Infinity 如何存储在内存中?

MATLAB中NaN是怎么产生的,又如何具体的去解决?

元组列表(字符串,浮点数)与 NaN 如何获得最小值?

如何在包含浮点数和 Nan 或 None 值的同一列中舍入浮点值?

4-浮点数运算