处理浮点异常

时间:2010-02-08 02:24:53

标签: c++ c exception floating-point signals

我不确定如何处理C或C ++中的浮点异常。从wiki中,有以下类型的浮点异常:

IEEE 754 specifies five arithmetic errors that are to be recorded in "sticky bits" (by default; note that trapping and other alternatives are optional and, if provided, non-default).  

* inexact, set if the rounded (and returned) value is different from the mathematically exact result of the operation.  
* underflow, set if the rounded value is tiny (as specified in IEEE 754) and inexact (or maybe limited to if it has denormalisation loss, as per the 1984 version of IEEE 754), returning a subnormal value (including the zeroes).  
* overflow, set if the absolute value of the rounded value is too large to be represented (an infinity or maximal finite value is returned, depending on which rounding is used).  
* divide-by-zero, set if the result is infinite given finite operands (returning an infinity, either +∞ or −∞).  
* invalid, set if a real-valued result cannot be returned (like for sqrt(−1), or 0/0), returning a quiet NaN.

当发生任何类型的上述异常时,程序会异常退出吗?或者程序会在没有提及任何内容的情况下执行此错误,因此难以调试错误?

像gcc这样的编译器是否能够针对某些明显的情况发出警告?

在对程序进行编码时,我可以做些什么来通知错误发生的位置以及发生错误时的类型,以便我可以在代码中轻松找到错误?请给出C和C ++案例的解决方案。

谢谢和问候!

6 个答案:

答案 0 :(得分:12)

有很多选项,但754引入的一般和默认哲学是 陷阱,而是产生特殊结果,例如可能或可能的无穷大没有出现在重要的结果中。

因此,测试各个操作状态的函数不会像测试结果表示的函数那样频繁使用。

参见,例如......

LIST OF FUNCTIONS

 Each of the functions that use floating-point values are provided in sin-
 gle, double, and extended precision; the double precision prototypes are
 listed here.  The man pages for the individual functions provide more
 details on their use, special cases, and prototypes for their single and
 extended precision versions.

 int fpclassify(double)
 int isfinite(double)
 int isinf(double)
 int isnan(double)
 int isnormal(double)
 int signbit(double)

更新: 对于那些真正认为FPU ops在默认情况下生成SIGFPE的人,我鼓励你尝试这个程序。您可以轻松生成下溢,溢出和被零除。你不会生成什么(除非你在最后一个存活的VAX或非754 RISC上运行它)是SIGFPE:

#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av) { return printf("%f\n", atof(av[1]) / atof(av[2])); }

答案 1 :(得分:6)

在Linux上,您可以使用GNU扩展feenableexcept(隐藏在该页面底部)打开浮点异常的捕获 - 如果您这样做,那么当异常时您将收到信号SIGFPE发生,您可以在调试器中捕获。请注意,有时信号会在实际导致问题的那个之后抛出浮点指令,在调试器中给出误导性的行信息!

答案 2 :(得分:4)

在使用Visual C ++的Windows上,您可以使用_control87() etc.控制取消屏蔽哪些浮点异常。未屏蔽的浮点异常会生成结构化异常,可以使用__try / __except(以及其他一些机制)来处理。这完全取决于平台。

如果将浮点异常置为屏蔽,则另一种检测这些条件的平台相关方法是使用_clear87() etc.清除浮点状态,执行计算,然后使用{{3查询浮点状态}}

这是否比DigitalRoss建议检查结果更好?在大多数情况下,事实并非如此。如果你需要检测(或控制)舍入(这不太可能),那么可能吗?

在使用Borland / CodeGear / Embarcadero C ++的Windows上,默认情况下会屏蔽某些浮点异常,这在使用未通过未屏蔽的浮点异常进行测试的第三方库时经常会出现问题。

答案 3 :(得分:2)

不同的编译器以不同的方式处理这些错误。

不精确性几乎总是数字除以绝对值大于1的结果(也许是通过trancendental函数)。用绝对值加上,减去和乘以数字> 1.0只能导致溢出。

下溢不会经常发生,并且在正常计算中可能不会成为问题,除了泰勒级数等迭代函数。

溢出是一个通常可以通过某种“无限”比较检测到的问题,不同的编译器会有所不同。

除以零是非常值得注意的,因为如果你没有错误处理程序,你的程序将(应该)崩溃。检查红利和除数将有助于避免这个问题。

无效答案通常会在没有打印某种DOMAIN错误的特殊错误处理程序的情况下被捕获。

[编辑]

这可能会有所帮助:( Sun的数值计算指南) http://docs.sun.com/source/806-3568/

答案 4 :(得分:1)

C99引入了处理浮点异常的函数。在浮点运算之前,您可以使用feclearexcept()清除任何未完成的异常。在操作之后,您可以使用fetestexcept()来测试设置了哪些异常标志。

答案 5 :(得分:0)

在Linux中,您可以通过捕获SIGFPE信号来捕获这些异常。如果您不采取任何措施,这些例外将终止您的计划。要设置处理程序,请使用信号函数,传递您希望捕获的信号,以及在信号触发时调用的函数。