在Windows C++中如何捕获Nan和Inf?

8
今天我痛苦地发现NaN和Inf存在严重的副作用。例如,您是否知道sqrtf(NaN)比sqrtf(10.123132)慢15倍以上,而sqrtf(-1)则慢30倍以上!?您计算出的垃圾需要荒谬的时间,而您甚至没有意识到它。

好吧,在Linux下,您可以通过在其发生时抛出异常来捕获NaN和Inf错误:

#include <fenv.h> 
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);

你在Windows系统下如何实现这个呢?
编辑: 基准测试代码:
float a,b;
a = 1.0 / 0;   //inf
a = -10;         //also nice
long c=0;
long time = SDL_GetTicks();

for (long i=1;i<=1000000;i++) {
   b=sqrt(a); 
}

ostringstream Help; Help << SDL_GetTicks()-time;

//RESULT SHEET
//sqrt(1): 21ms
//sqrt(10): 21ms
//sqrt(10.123): 20ms
//sqrt(-10);   390ms
//sqrt(+-NaN): 174ms
//sqrt(inf):  174

1
你是如何测量那个时间的?也许你应该防止异常发生,而不是隐藏它们? - Michał Szczygieł
1
使用 isinf()isnan() 来检查数值?http://msdn.microsoft.com/en-us/library/hh308344.aspx - Violet Giraffe
3
您可以使用 _controlfp() 函数开启异常处理。 - Hans Passant
1
我无法在我的笔记本电脑(core i5,ubuntu,gcc)上复现您的时间。您使用的是什么硬件/操作系统,以及您如何进行基准测试? - rici
我认为速度问题只是一个红鲱鱼,谨慎地检查NaN / Inf才是目的,启用这些异常是手段。 - congusbongus
显示剩余2条评论
2个回答

5

我想使用基本的编辑器(如geany)- _controlfp听起来很有前途。需要任何库链接吗? - Kenobi
我相信它是 CRT 的一部分。应该很容易尝试并查看。 - Nate Hekman
@NateHekman #pragma float_control/fp:accept 影响代码生成,而不是浮点异常是否启用。 - Sneftel

1
对我而言,只有使用 _controlfp 方法才有效。我使用了“安全”的实现方式,即:
 unsigned int current_word = 0; 
 _controlfp_s(&current_word, _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM); // raise exception on NaN (0xF)

#pragma和/fp:except在我的代码中没有任何(期望的)效果(该代码由集成到C++项目中的C代码组成)。

或者,更简洁地说-只需删除_EM_INVALID标志即可使NaN引发异常:

unsigned int current_word = 0; 
_controlfp_s(&current_word, 0, _EM_INVALID); // raise exception on NaN (set 0x10 bit to false)

是的,之前的回答者似乎没有理解代码生成和浮点状态控制之间的区别。但请注意,如果您想禁用可能会影响特定操作是否引发异常的优化,则“/fp:except”也可能非常重要。(对于面向性能的测试来说,这并不有用。) - Sneftel
好的,这就解释了为什么另外两个建议对我没有起作用 - 谢谢澄清! - Henning

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接