Joh*_*ike -1 c++ floating-point templates
我几乎 100% 肯定之前有人问过这个问题,但是我对此的搜索并没有得到令人满意的答案。
那么让我们开始吧。我所有的问题都来自这个小问题:-1.#IND000。所以基本上我的值要么是 nan 要么是无穷大,所以计算爆炸导致错误。
因为我使用浮点数,所以我一直在 C# 中使用 float.IsNan() 和 float.IsInfinity() 但是当我开始用 C++ 编码时,我还没有在 C++ 中找到等效的函数。所以我写了一个模板来检查浮点数是否为nan,如下所示:
template <typename T> bool isnan (T value)
{ return value != value; }
Run Code Online (Sandbox Code Playgroud)
但是我应该如何编写一个函数来定义浮点数是否为无限?毕竟我的 nan 检查是否正确完成?此外,我正在定时循环中进行 ckecks,因此模板应该快速运行。
谢谢你的时间!
注意:
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//isfiniteisnan宏/函数上使用上面的算术比较。
我发现您在这里使用的是 Microsoft 编译器。我没有安装。下面的内容都是参考gcc我的Arch盒子上的,即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(":(");
}
}
}
Run Code Online (Sandbox Code Playgroud)
这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
Run Code Online (Sandbox Code Playgroud)
请注意,包含 的分支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)
Run Code Online (Sandbox Code Playgroud)
看来是gcc不知道isnan做什么了!它使用 生成死分支,printf并生成对 的两个单独的调用isnan。
我的观点是,使用isnan宏/函数会混淆 gcc 的值分析。它不知道isnan(x)当且仅当x是 NaN。让编译器优化工作通常比为给定原语生成最快的代码重要得多。
您正在寻找std::isnan()和std::isinf()。鉴于这些函数作为标准库的一部分存在,您不应尝试自己编写这些函数。
现在,我一直怀疑这些函数不存在于 VS2010 附带的标准库中。在这种情况下,您可以使用 CRT 提供的功能来解决遗漏问题。具体有以下几种功能中声明float.h:_isnan(),_finite(x)和_fpclass()。
| 归档时间: |
|
| 查看次数: |
1085 次 |
| 最近记录: |