如何在C中使用nan和inf?

时间:2009-12-17 18:57:47

标签: c math

我有一个可以返回nan或inf的数值方法,如果有错误,并且为了测试目的,我想暂时强制它返回nan或inf以确保正确处理情况。是否有可靠的编译器独立的方法在C中创建nan和inf的值?

谷歌搜索大约10分钟后,我才能找到编译器相关的解决方案。

9 个答案:

答案 0 :(得分:76)

您可以测试您的实施是否包含它:

#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif

INFINITY的存在由C99(或至少是最新的草稿)保证,并且“扩展为float类型的常量表达式,表示正或无符号 无穷大,如果有的话;否则为float类型的正常量,在转换时溢出。“

NAN可以定义,也可以不定义,并且“当且仅当实现支持float类型的安静NaN时才定义。它扩展为float类型的常量表达式,表示安静的NaN。”

请注意,如果您要比较浮点值,请执行以下操作:

a = NAN;

即便如此,

a == NAN;

是假的。检查NaN的一种方法是:

#include <math.h>
if (isnan(a)) { ... }

您还可以执行:a != a来测试a是否为NaN。

C99中的isfinite()中还有isinf()isnormal()signbit()math.h个宏。

C99还有nan个功能:

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

(参考:n1256)。

Docs INFINITY Docs NAN

答案 1 :(得分:34)

没有编译器独立的方法,因为C(也不是C ++)标准都没有说浮点数学类型必须支持NAN或INF。

编辑:我刚检查了C ++标准的措辞,并说它们是这些函数(模板类numeric_limits的成员):

quiet_NaN() 
signalling_NaN()

wiill返回NAN表示“如果可用”。它没有扩展“如果可用”意味着什么,但可能是“如果实现的FP代表支持它们”。同样,还有一个功能:

infinity() 

返回正INF表示“如果可用”。

这些都在<limits>标题中定义 - 我猜测C标准有类似的东西(可能也“如果可用”),但我没有当前C99标准的副本。

答案 2 :(得分:20)

这适用于floatdouble

double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;

编辑: 正如有人已经说过,旧的IEEE标准说 这样的价值观应该引发陷阱。但新的编译器 几乎总是关闭陷阱并返回 给定值,因为陷阱会干扰错误 处理

答案 3 :(得分:19)

独立于编译器的方式,但不是与处理器无关的方式来获取这些:

int inf = 0x7F800000;
return *(float*)&inf;

int nan = 0x7F800001;
return *(float*)&nan;

这适用于任何使用IEEE 754浮点格式(x86都支持)的处理器。

更新:经过测试和更新。

答案 4 :(得分:12)

double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);

答案 5 :(得分:3)

<inf.h>

/* IEEE positive infinity.  */

#if __GNUC_PREREQ(3,3)
# define INFINITY   (__builtin_inff())
#else
# define INFINITY   HUGE_VALF
#endif

<bits/nan.h>
#ifndef _MATH_H
# error "Never use <bits/nan.h> directly; include <math.h> instead."
#endif


/* IEEE Not A Number.  */

#if __GNUC_PREREQ(3,3)

# define NAN    (__builtin_nanf (""))

#elif defined __GNUC__

# define NAN \
  (__extension__                                  \
   ((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; })  \
    { __l: 0x7fc00000UL }).__d)

#else

# include <endian.h>

# if __BYTE_ORDER == __BIG_ENDIAN
#  define __nan_bytes       { 0x7f, 0xc0, 0, 0 }
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
#  define __nan_bytes       { 0, 0, 0xc0, 0x7f }
# endif

static union { unsigned char __c[4]; float __d; } __nan_union
    __attribute_used__ = { __nan_bytes };
# define NAN    (__nan_union.__d)

#endif  /* GCC.  */

答案 6 :(得分:0)

我也很惊讶这些不是编译时间常数。但是我想你可以通过简单地执行返回这种无效结果的指令来轻松地创建这些值。除以0,记录为0,棕褐色为90,有点像。

答案 7 :(得分:0)

我通常使用

#define INFINITY (1e999)

const double INFINITY = 1e999

至少在IEEE 754上下文中起作用,因为最高可表示的双值大致为1e3081e3091e99999一样可以正常工作,但是三个九就足够了,令人难忘。由于这是双字面(在#define情况下)或实际Inf值,即使您使用的是128位(“long double”)浮点数,它也将保持无限。

答案 8 :(得分:0)

这是定义这些常量的简单方法,我很确定它是可移植的:

const double inf = 1.0/0.0;
const double nan = 0.0/0.0;

当我运行此代码时:

printf("inf  = %f\n", inf);
printf("-inf = %f\n", -inf);
printf("nan  = %f\n", nan);
printf("-nan = %f\n", -nan);

我得到:

inf  = inf
-inf = -inf
nan  = -nan
-nan = nan