如何在 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::isnan
和 std::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
为除inf
和nan
之外的所有值返回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 想要的 - 应该只为 inf
和 nan
值返回 true
,所以 !isfinite
会这样做。【参考方案3】:
虽然严格来说不是 C++03 的一部分,但如果您的编译器提供了标准 isfinite
、isinf
、isnan
。如果是这样,这些将是执行这些检查的最简单和最安全的方法。
【讨论】:
【参考方案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-x
是0
,并且比较成功。不过,我建议使用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++ 中检查无限和不确定的值?的主要内容,如果未能解决你的问题,请参考以下文章