如果出现错误,我有一个可以返回 nan 或 inf 的数值方法,出于测试目的,我想暂时强制它返回 nan 或 inf 以确保情况得到正确处理。是否有一种可靠的、独立于编译器的方法来在 C 中创建 nan 和 inf 的值?
谷歌搜索大约 10 分钟后,我只能找到依赖于编译器的解决方案。
您可以测试您的实现是否具有它:
#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif
的存在INFINITY
由 C99(或至少最新草案)保证,并且“扩展为表示正或无符号无穷大的浮点类型的常量表达式(如果可用);否则为在翻译时溢出的浮点类型的正常量。”
NAN
可以定义也可以不定义,并且“当且仅当实现支持浮点类型的安静 NaN 时才定义。它扩展为表示安静 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)。
没有编译器独立的方式来做到这一点,因为 C(或 C++)标准都没有说浮点数学类型必须支持 NAN 或 INF。
编辑:我刚刚检查了 C++ 标准的措辞,它说这些函数(模板类 numeric_limits 的成员):
quiet_NaN()
signalling_NaN()
将返回 NAN 表示“如果可用”。它没有扩展“如果可用”的含义,但大概类似于“如果实现的 FP 代表支持它们”。同样,还有一个功能:
infinity()
它返回一个正 INF 代表“如果可用”。
这些都在<limits>
标题中定义 - 我猜 C 标准有类似的东西(可能也是“如果可用”),但我没有当前 C99 标准的副本。
这适用于float
和double
:
double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;
编辑:正如有人已经说过的,旧的 IEEE 标准说这样的值应该引起陷阱。但是新的编译器几乎总是关闭陷阱并返回给定的值,因为陷阱会干扰错误处理。
一种独立于编译器的方式,但不是独立于处理器的方式来获得这些:
int inf = 0x7F800000;
return *(float*)&inf;
int nan = 0x7F800001;
return *(float*)&nan;
这应该适用于任何使用 IEEE 754 浮点格式(x86 可以)的处理器。
更新:测试和更新。
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);
<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. */
我通常使用
#define INFINITY (1e999)
或者
const double INFINITY = 1e999
这至少在 IEEE 754 上下文中有效,因为最高可表示的双精度值大致为1e308
. 1e309
会和 一样好用,1e99999
但是三个 9 就足够了,而且令人难忘。由于这要么是双精度文字(在这种#define
情况下)要么是实际Inf
值,因此即使您使用 128 位(“long double”)浮点数,它也将保持无限。
我也很惊讶这些不是编译时间常数。但是我想您可以通过简单地执行返回这种无效结果的指令来轻松地创建这些值。除以 0,0 的对数,90 的棕褐色,那种东西。
这是定义这些常量的简单方法,我很确定它是可移植的:
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