如何使用try ... catch来捕获浮点错误?

时间:2010-05-05 00:22:02

标签: c++ error-handling

我在visual studio express中使用c ++生成随机表达式树,用于遗传算法类型的程序。

因为它们是随机的,所以树通常会生成:除以零,溢出,下溢以及返回“inf”和其他字符串。我可以为字符串编写处理程序,但文献让我对其他人感到困惑。如果我理解正确,我必须先设置一些标志?

建议和/或指向某些文献的指针将不胜感激。 编辑:double变量中返回的值为1.#INF或-1。#IND。我把它们称为字符串是错误的。

4 个答案:

答案 0 :(得分:10)

根据 http://msdn.microsoft.com/en-us/library/aa289157%28v=vs.71%29.aspx#floapoint_topic8
似乎可以在MSVC中抛出C ++异常

创建例外类:

class float_exception : public std::exception {};
class fe_denormal_operand : public float_exception {};
class fe_divide_by_zero : public float_exception {};
class fe_inexact_result : public float_exception {};
class fe_invalid_operation : public float_exception {};
class fe_overflow : public float_exception {};
class fe_stack_check : public float_exception {};
class fe_underflow : public float_exception {};

使用结构化异常处理程序将C ++映射到FPU异常

void se_fe_trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
    switch (u)
    {
    case STATUS_FLOAT_DENORMAL_OPERAND:   throw fe_denormal_operand();
    case STATUS_FLOAT_DIVIDE_BY_ZERO:     throw fe_divide_by_zero();
    etc...
    };
}
. . .
_set_se_translator(se_fe_trans_func);

然后您可以使用try catch

try
{
    floating-point code that might throw divide-by-zero 
   or other floating-point exception
}
catch(fe_divide_by_zero)
{
    cout << "fe_divide_by_zero exception detected" << endl;
}
catch(float_exception)
{
    cout << "float_exception exception detected" << endl;
}

答案 1 :(得分:7)

你确定要抓住它们而不是忽略它们吗?假设你只是想忽略它们:

看到这个: http://msdn.microsoft.com/en-us/library/c9676k6h.aspx

对于_MCW_EM掩码,清除掩码设置异常,这允许硬件异常;设置掩码会隐藏异常。

所以你想要做这样的事情:

#include <float.h>
#pragma fenv_access (on)

void main()
{
    unsigned int fp_control_word;
    unsigned int new_fp_control_word;

    _controlfp_s(&fp_control_word, 0, 0);

    // Make the new fp env same as the old one,
    // except for the changes we're going to make
    new_fp_control_word = fp_control_word | _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT;
    //Update the control word with our changes
    _controlfp_s(&fp_control_word, new_fp_control_word, _MCW_EM)


}

这里的一些混淆可能是使用“例外”一词。在C ++中,这通常指的是语言内置的异常处理系统。浮点异常完全是一个不同的野兽。标准FPU需要支持的例外都在IEEE-754中定义。这些发生在浮点单元内部,根据浮点单元的控制标志的设置方式,可以执行不同的操作。通常会发生以下两种情况之一: 1)忽略异常,FPU设置一个标志,指示其状态寄存器中发生错误。 2)FPU不会忽略该异常,因此生成中断,并且调用为浮点错误设置的任何中断处理程序。通常,这对您有好处,比如让您在调试器中的那行代码中断或生成核心文件。

您可以在此处找到有关IEE-754的更多信息:http://www.openwatcom.org/ftp/devel/docs/ieee-754.pdf

一些额外的浮点引用: http://docs.sun.com/source/806-3568/ncg_goldberg.html http://floating-point-gui.de/

答案 2 :(得分:1)

C ++运行时环境在这里没有任何帮助。您必须自己在代码中明确执行这些检查。当然,除非你正在调用的函数正在进行这些检查 - 在这种情况下,它取决于它们在出错时的行为方式。

让我解释一下:

double divide(double a, double b) {
    return a / b;  // undefined if b is zero
}

实际上应该是

double divide(double a, double b) {
    if( b == 0 ) {
        // throw, return, flag, ...  you choose how to signal the error
    }
    return a / b;  // b can't possibly be zero here
}

如果代码在被零除的情况下失败,那么你就不得不深入挖掘,以便在出现错误威胁的情况下找到它的作用。它扔了吗?设置一面旗帜?询问作者和/或阅读来源。

以下是例外情况的示例:

struct bad_value : public std::exception { };

double divide(double a, double b) {
    if( b == 0 ) throw bad_value("Division by zero in divide()");
    return a / b;  // b can't possibly be zero here
}

// elsewhere (possibly in a parallel universe) ...

    try {
        double r1 = divide(5,4);
        double r2 = divide(5,0);
    } catch( bad_value e ) {
        // ...
    }

答案 3 :(得分:-2)

从未尝试过,但假设除以零会引发异常,您可以将代码包装在try / catch中,如下所示:

试 {   //潜在除以零... } 抓住(...) {   // ...捕获所有异常 }