在C ++中处理浮点异常 [英] Handling Floating-Point exceptions in C++

查看:158
本文介绍了在C ++中处理浮点异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现浮点模型/错误问题很混乱。这是一个我不熟悉的领域,我不是一个低级C / asm程序员,所以我非常感谢一些建议。

I'm finding the floating-point model/error issues quite confusing. It's an area I'm not familiar with and I'm not a low level C/asm programmer, so I would appreciate a bit of advice.

我有一个大使用VS2012(VC11)构建的C ++应用程序,我已经配置为抛出浮点异常(或者更精确地说,允许C ++运行时和/或硬件抛出fp异常) - 并且它在相当多的发布(优化)构建,但不在调试构建中。我假设这是由于优化和浮点模型(虽然编译器/ fp:precise开关设置为发布和调试版本)。

I have a largish C++ application built with VS2012 (VC11) that I have configured to throw floating-point exceptions (or more precisely, to allow the C++ runtime and/or hardware to throw fp-exceptions) - and it is throwing quite a lot of them in the release (optimized) build, but not in the debug build. I assume this is due to the optimizations and perhaps the floating-point model (although the compiler /fp:precise switch is set for both the release and debug builds).

我的第一个问题涉及到管理应用程序的调试。我想控制fp异常抛出的地方,他们掩蔽的地方。这是需要的,因为我调试(优化)发布版本(这是fp异常发生) - 我想禁用fp异常在某些功能,我已经检测到问题,所以我可以找到新的FP问题。但我很困惑的使用_controlfp_s做这个(这工作正常)和编译器(和#pragma float_control)开关/ fp:except(似乎没有效果)之间的区别。这两种机制之间有什么区别?他们应该对fp异常有相同的效果吗?

My first question relates to managing the debugging of the app. I want to control where fp-exceptions are thrown and where they are "masked". This is needed because I am debugging the (optimized) release build (which is where the fp-exceptions occur) - and I want to disable fp-exceptions in certain functions where I have detected problems, so I can then locate new FP problems. But I am confused by the difference between using _controlfp_s to do this (which works fine) and the compiler (and #pragma float_control) switch "/fp:except" (which seems to have no effect). What is the difference between these two mechanisms? Are they supposed to have the same effect on fp exceptions?

其次,我得到一些浮点堆栈检查异常 - 包括似乎是在调用GDI + dll时抛出。搜索web,几个提到这个异常似乎表明它是由于编译器错误。这是一般的情况吗?如果是这样,我应该怎么工作呢?最好是为问题函数禁用编译器优化,或者仅在有问题的代码区域中禁用fp-exceptions,如果没有返回任何错误的浮点值?例如,在抛出此异常的GDI +调用(GraphicsPath :: GetPointCount)中,实际返回的整数值似乎是正确的。目前,我使用_controlfp_s在GDI +调用之前立即禁用fp-exceptions - 然后再次使用它来在调用后直接重新启用异常。

Secondly, I am getting a number of "Floating-point stack check" exceptions - including one that seems to be thrown in a call to the GDI+ dll. Searching around the web, the few mentions of this exception seem to indicate it is due to compiler bugs. Is this generally the case? If so, how should I work round this? Is it best to disable compiler optimizations for the problem functions, or to disable fp-exceptions just for the problematic areas of code if there don't appear to be any bad floating-point values returned? For example, in the GDI+ call (to GraphicsPath::GetPointCount) that throws this exception, the actual returned integer value seems correct. Currently I'm using _controlfp_s to disable fp-exceptions immediately prior to the GDI+ call – and then use it again to re-enable exceptions directly after the call.

最后,我的应用程序确实做了很多浮点计算,需要稳健可靠,但不一定非常准确。应用程序的本质是浮点值通常表示概率,因此本质上有些不精确。但是,我想要捕获任何纯逻辑错误,如除以零。这是什么是最好的fp模型?目前为:

Finally, my application does make a lot of floating-point calculations and needs to be robust and reliable, but not necessarily hugely accurate. The nature of the application is that the floating-point values generally indicate probabilities, so are inherently somewhat imprecise. However, I want to trap any pure logic errors, such as divide by zero. What is the best fp model for this? Currently I am:


  • 使用_controlfp_s和SIGFPE信号处理程序捕获所有fp异常(即EM_OVERFLOW | EM_UNDERFLOW | EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID)

  • 已启用非零(DAZ)和清零(FTZ)(即_MM_SET_FLUSH_ZERO_MODE(_MM_DENORMALS_ZERO_ON))和

  • 我使用默认的VC11编译器设置/ fp:precise with / fp:except没有指定。

这是最好的模型吗?

感谢和问候!

推荐答案

来自Bruce Dawson的博文(链接) 。

Most of the the following information comes from Bruce Dawson's blog post on the subject (link).

由于使用C ++,您可以创建一个RAII类,以范围方式启用或禁用浮点异常。这让你有更大的控制,所以你只暴露异常状态到你的代码,而不是手动管理调用_controlfp_s()自己。此外,以这种方式设置的浮点异常状态是系统范围的,因此记住控制字的先前状态并在需要时恢复它是真正可取的。

Since you're working with C++, you can create a RAII class that enables or disables floating point exceptions in a scoped manner. This lets you have greater control so that you're only exposing the exception state to your code, rather than manually managing calling _controlfp_s() yourself. In addition, floating point exception state that is set this way is system wide, so it's really advisable to remember the previous state of the control word and restore it when needed. RAII can take care of this for you and is a good solution for the issues with GDI+ that you're describing.

异常标志_EM_OVERFLOW,_EM_ZERODIVIDE和_EM_INVALID分别是用来描述GDI +的问题的解决方案。最重要的是要考虑。 _EM_OVERFLOW在正或负无穷大是计算结果时上升,而_EM_INVALID在结果是信号NaN时上升。 _EM_UNDERFLOW可以安全忽略;它会在您的计算结果非零并且在-FLT_MIN和FLT_MIN(换句话说,当您生成反规范时)发出信号。 _EM_INEXACT由于浮点运算的性质而被频繁地引用以至于无法实际使用,但是如果在某些情况下尝试跟踪不精确的结果,则可能会提供信息。

The exception flags _EM_OVERFLOW, _EM_ZERODIVIDE, and _EM_INVALID are the most important to account for. _EM_OVERFLOW is raised when positive or negative infinity is the result of a calculation, whereas _EM_INVALID is raised when a result is a signaling NaN. _EM_UNDERFLOW is safe to ignore; it signals when your computation result is non-zero and between -FLT_MIN and FLT_MIN (in other words, when you generate a denormal). _EM_INEXACT is raised too frequently to be of any practical use due to the nature of floating point arithmetic, although it can be informative if trying to track down imprecise results in some situations.

SIMD代码增加了更多的皱纹;因为你没有明确指出使用SIMD我将省略一个讨论,除了注意指定除了/ fp:fast之外的任何东西可以禁用您的代码在VS 2012的自动矢量化;有关详情,请参阅此答案

SIMD code adds more wrinkles to the mix; since you don't indicate using SIMD explicitly I'll leave out a discussion of that except to note that specifying anything other than /fp:fast can disable automatic vectorization of your code in VS 2012; see this answer for details on this.

这篇关于在C ++中处理浮点异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆