如何正确检查一个值是否为无穷大或在c++(msvc2010)
How to properly check if a value is infinite or nan ic c++(msvc2010)
我几乎100%肯定以前有人问过这个问题,但是我对这个问题的搜索并没有导致一个令人满意的答案。
让我们开始吧。我所有的问题都来自这个小问题:-1.#IND000。所以基本上我的值要么是nan要么是infinite,所以计算会爆炸导致错误。
因为我正在使用浮点数,所以我一直在c#中使用float.IsNan()和float.IsInfinity()但是当我开始用c++编码时,我还没有在c++中找到相当的函数。所以我写了一个模板来检查浮点数是否为nan,如下所示:
template <typename T> bool isnan (T value)
{ return value != value; }
但是我应该如何写一个函数来定义如果浮点数是无限的?毕竟我的检查做得好吗?另外,我在一个定时循环中做检查,所以模板应该动作快。
谢谢你的时间!
您正在寻找std::isnan()
和std::isinf()
。您不应该尝试自己编写这些函数,因为它们是标准库的一部分。
现在,我有一个挥之不去的疑问,这些函数不存在于VS2010附带的标准库中。在这种情况下,您可以通过使用CRT提供的函数来解决遗漏问题。具体来说,float.h
中声明的函数有:_isnan()
、_finite(x)
和_fpclass()
。
注意:
-
x
是NaN当且仅当x != x
。 -
x
是NaN或无穷大当且仅当x - x != 0
。 -
x
是零或无穷大当且仅当x + x == x
。 -
x
是零当且仅当x == 0
。 - 如果
FLT_EVAL_METHOD
是0
或1
,则x
是无穷大当且仅当x + DBL_MAX == x
。 -
x
是正无穷当且仅当x + infinity == x
。
我不认为使用上面的比较函数而不是标准库函数有什么错,即使这些标准库函数存在。事实上,在评论中与David Heffernan讨论后,我建议在isinf
/isfinite
/isnan
宏/函数上使用上面的算术比较。
我看到你在这里使用微软编译器。我没有安装。下面的内容都是参考我的Arch盒子上的gcc
,即gcc version 4.9.0 20140521 (prerelease) (GCC)
完成的,所以这最多是一个可移植性说明。在你的编译器中尝试类似的东西,看看哪些变体(如果有的话)告诉编译器发生了什么,哪些只是让它放弃。
考虑以下代码:
int foo(double x) {
return x != x;
}
void tva(double x) {
if (!foo(x)) {
x += x;
if (!foo(x)) {
printf(":(");
}
}
}
这里foo
是isnan
的实现。x += x
不会产生NaN,除非x
之前是NaN。以下是为tva
生成的代码:
0000000000000020 <_Z3tvad>:
20: 66 0f 2e c0 ucomisd %xmm0,%xmm0
24: 7a 1a jp 40 <_Z3tvad+0x20>
26: f2 0f 58 c0 addsd %xmm0,%xmm0
2a: 66 0f 2e c0 ucomisd %xmm0,%xmm0
2e: 7a 10 jp 40 <_Z3tvad+0x20>
30: bf 00 00 00 00 mov $0x0,%edi
35: 31 c0 xor %eax,%eax
37: e9 00 00 00 00 jmpq 3c <_Z3tvad+0x1c>
3c: 0f 1f 40 00 nopl 0x0(%rax)
40: f3 c3 repz retq
注意,没有生成包含printf
的分支。如果我们用isnan
代替foo
会发生什么?
00000000004005c0 <_Z3tvad>:
4005c0: 66 0f 28 c8 movapd %xmm0,%xmm1
4005c4: 48 83 ec 18 sub $0x18,%rsp
4005c8: f2 0f 11 4c 24 08 movsd %xmm1,0x8(%rsp)
4005ce: e8 4d fe ff ff callq 400420 <__isnan@plt>
4005d3: 85 c0 test %eax,%eax
4005d5: 75 17 jne 4005ee <_Z3tvad+0x2e>
4005d7: f2 0f 10 4c 24 08 movsd 0x8(%rsp),%xmm1
4005dd: 66 0f 28 c1 movapd %xmm1,%xmm0
4005e1: f2 0f 58 c1 addsd %xmm1,%xmm0
4005e5: e8 36 fe ff ff callq 400420 <__isnan@plt>
4005ea: 85 c0 test %eax,%eax
4005ec: 74 0a je 4005f8 <_Z3tvad+0x38>
4005ee: 48 83 c4 18 add $0x18,%rsp
4005f2: c3 retq
4005f3: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4005f8: bf 94 06 40 00 mov $0x400694,%edi
4005fd: 48 83 c4 18 add $0x18,%rsp
400601: e9 2a fe ff ff jmpq 400430 <printf@plt>
400606: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
看来gcc
不知道isnan
在做什么!它使用printf
生成死分支,并生成对isnan
的两个单独调用。
我的观点是,使用isnan
宏/函数会混淆gcc的值分析。它不知道isnan(x)
当且仅当x
是NaN。让编译器优化工作通常比为给定原语生成尽可能快的代码重要得多。
- 无穷大而循环时具有递归函数
- 在C++中比较无穷大和无穷大
- Rand()大小写开关在多次迭代后运行到无穷大
- 无穷大与 NAN 值
- Android Studio 调试原生代码 lldb 服务器工作无穷大
- Matlab 如何知道有一个 .mex64 文件并避免无穷大"compiling"循环
- 比较无穷大
- 为什么双重类型返回无穷大
- 如何获得从负无穷大到无穷大的范围以在 0 到 1 的范围内表示
- c++ std 的 inf 的行为是否与常识无穷大完全一样
- 无穷大不是constexpr
- Qt Creator 2.6.1 + Qt 5 + C++11 + MSVC2010 compiler
- 零减去零等于无穷大
- 浮点变量变为无穷大
- 如何避免无穷大递归中的堆栈溢出
- 为什么math.h的pow函数返回无穷大的值
- 是0除以无穷大,保证为0
- 在物理计算中表示无穷大
- 错误:“无穷大”未命名类型
- 如何正确检查一个值是否为无穷大或在c++(msvc2010)