如何在C中使用nan和inf?

发布于 2024-08-15 09:55:30 字数 155 浏览 6 评论 0原文

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

经过大约 10 分钟的谷歌搜索后,我只能找到依赖于编译器的解决方案。

I have a numerical method that could return nan or inf if there was an error, and for testing purposed I'd like to temporarily force it to return nan or inf to ensure the situation is being handled correctly. Is there a reliable, compiler-independent way to create values of nan and inf in C?

After googling for about 10 minutes I've only been able to find compiler dependent solutions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

零崎曲识 2024-08-22 09:55:30

您可以测试您的实现是否具有它:

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

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

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

请注意,如果您正在比较浮点值,并且 do:

a = NAN;

即使这样,

a == NAN;

也是 false。检查 NaN 的一种方法是:

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

您还可以执行以下操作: < code>a != a 来测试 a 是否为 NaN。

还有 isfinite()isinf()、< C99 中 math.h 中的 code>isnormal() 和 signbit()

也有 nan 函数

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

:(参考:n1256)


文档 NAN

You can test if your implementation has it:

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

The existence of INFINITY is guaranteed by C99 (or the latest draft at least), and "expands to a constant expression of type float representing positive or unsigned
infinity, if available; else to a positive constant of type float that overflows at translation time."

NAN may or may not be defined, and "is defined if and only if the implementation supports quiet NaNs for the float type. It expands to a constant expression of type float representing a quiet NaN."

Note that if you're comparing floating point values, and do:

a = NAN;

even then,

a == NAN;

is false. One way to check for NaN would be:

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

You can also do: a != a to test if a is NaN.

There is also isfinite(), isinf(), isnormal(), and signbit() macros in math.h in C99.

C99 also has nan functions:

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

(Reference: n1256).

Docs INFINITY
Docs NAN

ヤ经典坏疍 2024-08-22 09:55:30

没有独立于编译器的方法可以做到这一点,因为 C(或 C++)标准都没有规定浮点数学类型必须支持 NAN 或 INF。

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

quiet_NaN() 
signalling_NaN()

将返回 NAN 表示“如果可用”。它没有扩展“如果可用”的含义,但大概是“如果实现的 FP 代表支持它们”之类的内容。类似地,有一个函数:

infinity() 

它返回一个正的 INF 表示“如果可用”。

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

There is no compiler independent way of doing this, as neither the C (nor the C++) standards say that the floating point math types must support NAN or INF.

Edit: I just checked the wording of the C++ standard, and it says that these functions (members of the templated class numeric_limits):

quiet_NaN() 
signalling_NaN()

wiill return NAN representations "if available". It doesn't expand on what "if available" means, but presumably something like "if the implementation's FP rep supports them". Similarly, there is a function:

infinity() 

which returns a positive INF rep "if available".

These are both defined in the <limits> header - I would guess that the C standard has something similar (probably also "if available") but I don't have a copy of the current C99 standard.

还如梦归 2024-08-22 09:55:30

这适用于 floatdouble

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

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

This works for both float and double:

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

Edit:
As someone already said, the old IEEE standard said that
such values should raise traps. But the new compilers
almost always switch the traps off and return the
given values because trapping interferes with error
handling.

帝王念 2024-08-22 09:55:30
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);
半透明的墙 2024-08-22 09:55:30

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

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

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

这应该适用于任何使用 IEEE 754 浮点格式的处理器(x86 可以)。

更新:已测试并更新。

A compiler independent way, but not processor independent way to get these:

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

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

This should work on any processor which uses the IEEE 754 floating point format (which x86 does).

UPDATE: Tested and updated.

彼岸花ソ最美的依靠 2024-08-22 09:55:30
<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.  */
<inf.h>

/* IEEE positive infinity.  */

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

and

<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.  */
太阳公公是暖光 2024-08-22 09:55:30

我通常使用

#define INFINITY (1e999)

or

const double INFINITY = 1e999

,它至少在 IEEE 754 上下文中有效,因为可表示的最高双精度值大约为 1e3081e309 的效果与 1e99999 一样好,但三个 9 就足够了并且容易记住。由于这要么是双精度字面量(在 #define 情况下),要么是实际的 Inf 值,因此即使您使用 128 位(“long双”)浮动。

I usually use

#define INFINITY (1e999)

or

const double INFINITY = 1e999

which works at least in IEEE 754 contexts because the highest representable double value is roughly 1e308. 1e309 would work just as well, as would 1e99999, but three nines is sufficient and memorable. Since this is either a double literal (in the #define case) or an actual Inf value, it will remain infinite even if you're using 128-bit (“long double”) floats.

坏尐絯 2024-08-22 09:55:30

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

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

Here is a simple way to define those constants, and I'm pretty sure it's portable:

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

When I run this code:

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

I get:

inf  = inf
-inf = -inf
nan  = -nan
-nan = nan
梦年海沫深 2024-08-22 09:55:30

在 MSVC 中,在 Correct_math.h 中定义了以下内容,该内容包含在 math.h 中:

#ifndef _HUGE_ENUF
    #define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
#endif

#define INFINITY   ((float)(_HUGE_ENUF * _HUGE_ENUF))
#define HUGE_VAL   ((double)INFINITY)
#define HUGE_VALF  ((float)INFINITY)
#define HUGE_VALL  ((long double)INFINITY)
#ifndef _UCRT_NEGATIVE_NAN
// This operation creates a negative NAN adding a - to make it positive
#define NAN        (-(float)(INFINITY * 0.0F))
#else
// Keep this for backwards compatibility
#define NAN        ((float)(INFINITY * 0.0F))
#endif

In MSVC, the following is defined in correct_math.h, which is included in math.h:

#ifndef _HUGE_ENUF
    #define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
#endif

#define INFINITY   ((float)(_HUGE_ENUF * _HUGE_ENUF))
#define HUGE_VAL   ((double)INFINITY)
#define HUGE_VALF  ((float)INFINITY)
#define HUGE_VALL  ((long double)INFINITY)
#ifndef _UCRT_NEGATIVE_NAN
// This operation creates a negative NAN adding a - to make it positive
#define NAN        (-(float)(INFINITY * 0.0F))
#else
// Keep this for backwards compatibility
#define NAN        ((float)(INFINITY * 0.0F))
#endif
幸福丶如此 2024-08-22 09:55:30

我也很惊讶这些不是编译时间常数。但我想您可以通过简单地执行返回此类无效结果的指令来轻松创建这些值。除以 0、0 的对数、90 的 tan,诸如此类。

I'm also surprised these aren't compile time constants. But I suppose you could create these values easily enough by simply executing an instruction that returns such an invalid result. Dividing by 0, log of 0, tan of 90, that kinda thing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文