如何在 C++ 中检查无限和不确定的值?

Posted

技术标签:

【中文标题】如何在 C++ 中检查无限和不确定的值?【英文标题】:How do you check for infinite and indeterminate values in C++? 【发布时间】:2010-09-29 11:29:18 【问题描述】:

在我的程序中,当一个值被零除时,通常会出现无穷大。当我将零除以零时,我变得不确定。

在 C++ 中,无穷大由 1.#INF 表示。不确定由 -1.#IND 表示。问题是如何测试一个变量是无限的还是不确定的。检查无穷大相对简单:您可以在特定的 C++ 中找到无穷大定义。对于我的情况(VS2003),它是 std::numeric_limits::infinity()。您必须包含“限制”才能使用它。您可以将此无限值分配给变量,然后将其与某个值进行比较,以检查该值是否为无限。

Indeterminate 有点棘手,因为您无法将不确定的值与其他值进行比较。任何比较都返回 false。您可以使用此属性通过将其与自身进行比较来检测不确定的值。假设您有一个名为 aVal 的双变量。在正常情况下,aVal != aVal 返回 false。但如果值不确定,aIndVal != aIndVal 返回真。无限值不存在这种奇怪的情况,即 aInfVal != aInfVal 总是返回 false。

这里有两个函数可用于检查不确定值和无限值:

#include "limits.h"
#include "math.h"

bool isIndeterminate(const double pV)

    return (pV != pV);
 

bool isInfinite(const double pV)

    return (fabs(pV) == std::numeric_limits::infinity())

这些检查有没有更好的方法,我有什么遗漏吗?

【问题讨论】:

这是一个page,它解释了如何测试无穷大等。查看函数 isNumber 和 isFiniteNumber。 如何更好?一个使用标准库来获得一个正确的表示进行比较,另一个使用语言保证的属性(与自身比较产生错误)。这两个函数都简单易读。没有比这更好的了,不是吗? 确实如此。这两个功能是我的初步想法,想知道我是否遗漏了什么。但我想他们还好。 “indeterminate”并不是你想的那个意思,它是用来描述未初始化变量和悬空指针的内容。 0.0 / 0.0 的结果是 NaN,而不是“不确定”。 【参考方案1】:

对于 Visual Studio,我会使用 _isnan_finite,或者可能是 _fpclass

但如果您可以访问支持 C++11 的标准库和编译器,则可以使用 std::isnanstd::isinf

【讨论】:

虽然这肯定是一种解决方案,但不应将其标记为答案。它是非常特定于平台的,几乎在所有情况下都应该避免。尤其是现在 C++11 的 std::isinf 和家族出现了。但即使你有一个旧的编译器,我也不会使用这个仅限 Microsoft 的解决方案。 还有std::isfinite【参考方案2】:

虽然 C++03 不提供 C99 的 isnan 和 isinf,但 C++11 将它们标准化为 functions。如果您可以使用 C++11 而不是严格的 C++03,那么这些将是更简洁的选择,避免使用宏、compiler built-ins 和平台相关函数。

C++11 的std::isfinite 为除infnan 之外的所有值返回true;所以!isfinite 应该一次性检查无限和不确定的值。

【讨论】:

如果你没有 C++11,Boost.Math 有实现。 boost.org/doc/libs/1_54_0/libs/math/doc/html/math_toolkit/… 从@legends2k 发布的链接看来,!std::isnormal() 是最好的测试。 您的意思是写std::isfinite!isnormal 将返回 true 即使是 0,这不是 OP 想要的 - 应该只为 infnan 值返回 true,所以 !isfinite 会这样做。【参考方案3】:

虽然严格来说不是 C++03 的一部分,但如果您的编译器提供了标准 头文件的一些新 C99 功能,那么您可以访问以下“类函数宏”: isfiniteisinfisnan。如果是这样,这些将是执行这些检查的最简单和最安全的方法。

【讨论】:

【参考方案4】:

您也可以将它们用作严格的仅限 C++ 的解决方案。除了通过使用类型特征来增加安全性之外,它们并没有真正提供比 OP 的解决方案更多的东西,而且在 is_inf 的情况下可能是最小的速度提升。

template <bool> struct static_assert;
template <> struct static_assert<true>  ;

template<typename T>
inline bool is_NaN(T const& x) 
    static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_quiet_NaN>));
    return std::numeric_limits<T>::has_quiet_NaN and (x != x);


template <typename T>
inline bool is_inf(T const& x) 
    static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_infinity>));
    return x == std::numeric_limits<T>::infinity() or x == -std::numeric_limits<T>::infinity();

(谨防自制static_assert

【讨论】:

据我所知,您还应该将 ::is_iec559 放入静态断言中,因为 x!=x 仅在您的实现实现 ieee754 标准 ***.com/questions/332705/… 时才有效(但我对此不确定。如果您知道更多,请发表评论) 好问题。我不知道。请随意更改我的答案。特别是,我不知道可以选择哪些替代实现以及它们为 NaN 值提供的规则/保证。【参考方案5】:

有来自 C99 或 POSIX 或我认为的 isfinite

一种骇人听闻的方法是测试x-x == 0;如果x 是无限或NaN,则x-x 是NaN,因此比较失败,而如果x 是有限的,则x-x0,并且比较成功。不过,我建议使用isfinite,或者将此测试打包成一个函数/宏,称为isfinite,这样你就可以在时机成熟时摆脱它。

【讨论】:

【参考方案6】:
if (x!=x)              ... then x is nan
if (x>0 && x/x != x/x) ... then x is +inf
if (x<0 && x/x != x/x) ... then x is -inf

这也可能有效(但涉及调用 exp() 和测试双精度数的相等性):

if (exp(-x)==0.) ... then x is inf
if (exp(x)==0.)  ... then x is -inf

【讨论】:

以上是关于如何在 C++ 中检查无限和不确定的值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 的条件语句中检查变量类型?

如何在 C++ 中检查用户输入

如何检查字符串是不是包含列表的任何元素并获取元素的值?

如何在 C++ 中使用 Detours 扩展程序内函数而不进入无限循环?

如何检查文件是不是存在于 C++ 中? [复制]

在 Linux 和 BSD 中使用和不使用 shebang 执行 Bash 脚本