我几乎100%肯定以前曾经问过这个问题,但我对此的搜索并没有带来满意的感谢。
让我们开始吧。我的所有问题都来自这个小问题:-1。#IND000。 所以基本上我的价值是纳米或无限,因此计算结果爆炸导致错误。
因为我正在使用浮点数,所以我一直在C#中使用float.IsNan()和float.IsInfinity() 但是当我开始用C ++编写代码时,我还没有在C ++中找到相同的函数。 所以我写了一个模板来检查浮点数是否为nan,如下所示:
template <typename T> bool isnan (T value)
{ return value != value; }
但是我该如何编写一个函数来定义float是否是无限的?毕竟我的南方检查是否正确完成?此外,我正在定时循环中执行ckecks,因此模板应该快速执行。
谢谢你的时间!
答案 0 :(得分:3)
您正在寻找std::isnan()
和std::isinf()
。您不应该尝试自己编写这些函数,因为它们作为标准库的一部分存在。
现在,我怀疑这些功能在VS2010附带的标准库中不存在。在这种情况下,您可以使用CRT提供的功能来解决遗漏问题。具体而言,float.h
中声明了以下函数:_isnan()
,_finite(x)
和_fpclass()
。
答案 1 :(得分:0)
请注意:
x
是NaN当且仅当x != x
。x
。时,x - x != 0
为NaN或无穷大
当且仅当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
宏/函数上使用上面的算术比较。
我看到你在这里使用的是Microsoft编译器。我没有安装。以下内容全部参考了我的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
除非x
之前是NaN,否则不会产生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
的分支。如果我们将foo
替换为isnan
,会发生什么?
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)
是NaN时,它不知道x
。编译器优化工作通常比为给定原语生成最快的代码重要得多。