C++ 如何使用try…catch来捕获浮点错误?

C++ 如何使用try…catch来捕获浮点错误?,c++,error-handling,C++,Error Handling,我在VisualStudioExpress中使用C++生成用于遗传算法类型程序的随机表达式树。 因为它们是随机的,所以树通常会生成:除零、溢出、下溢以及返回“inf”和其他字符串。我可以为字符串编写处理程序,但是文学作品让我对其他的感到困惑。如果我理解正确,我必须先设置一些标志 建议和/或参考一些文献将不胜感激。 编辑:双变量中返回的值是1.#INF或-1.#IND。我错误地将它们称为字符串。从未尝试过,但假设除以零会引发异常,您可以将代码包装成如下try/catch: #include <

我在VisualStudioExpress中使用C++生成用于遗传算法类型程序的随机表达式树。 因为它们是随机的,所以树通常会生成:除零、溢出、下溢以及返回“inf”和其他字符串。我可以为字符串编写处理程序,但是文学作品让我对其他的感到困惑。如果我理解正确,我必须先设置一些标志

建议和/或参考一些文献将不胜感激。
编辑:双变量中返回的值是1.#INF或-1.#IND。我错误地将它们称为字符串。

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

#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++运行环境对这里没有什么帮助。您必须在代码中显式地自己执行这些检查。当然,除非您调用的函数正在执行这些检查——在这种情况下,这取决于它们在发生错误时的行为

让我解释一下:

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 ) {
        // ...
    }

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

见此:

对于_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)


}
#包括
#布拉格马-芬沃通道(on)
void main()
{
无符号整型fp_控制_字;
无符号整型新控制字;
_控制fp_s(&fp_控制字,0,0);
//使新的fp env与旧的相同,
//除了我们要做的改变
new_fp_control_word=fp_control_word|u EM_无效| u EM_非正规| u EM_零除| u EM_溢出| u EM_下溢| u EM_不精确;
//用我们的更改更新控制字
_控制字(和控制字、新控制字、MCW字)
}
这里的一些混淆可能是关于“例外”一词的使用。在C++中,通常指的是语言内置的异常处理系统。浮点异常完全是另一回事。标准FPU需要支持的例外情况均在IEEE-754中定义。这些发生在浮点单元内部,根据浮点单元控制标志的设置方式,浮点单元可以执行不同的操作。通常会发生以下两种情况之一: 1) 异常将被忽略,FPU将设置一个标志,指示其状态寄存器中发生错误。 2) FPU不会忽略该异常,因此会生成一个中断,并调用为浮点错误设置的任何中断处理程序。通常,这会为您带来一些好处,比如使您在调试器中的代码行中断,或者生成一个核心文件

您可以在IEE-754上找到更多信息:

一些附加的浮点引用: 根据 ,
在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 {};

使用结构化异常处理程序

向FPU异常映射MAP C++
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;
}
试试看
{
可能抛出被零除的浮点代码
或其他浮点异常
}
捕获(fe除以0)
{

CUT C++不命令任何操作都应该抛出异常。它们导致未定义的行为。(可能崩溃,或抛出异常,或不做任何事情,O…)但是C99和POSIX确实指定了这些东西,并且提供了一个数字异常接口。但是,如果彼得得到的是字符串而不是FP无穷大,那么它是否有控制实际数字的原因还不清楚。这是错误的,因为C++运行时环境对这里没有帮助。它不会因为WH以外的任何原因而抛出异常。程序员特别要求抛出for.dthorpe:事实上,我并没有假设它运行在x86处理器上。MSDN文档明确指出_controlfp_s是新的“独立于平台的”这样做的方式。我怀疑平台无关性指的是CPU类型,因为显然并非所有x86操作系统都具有此功能-只要他在windows平台上执行此操作,他应该就可以了。还请注意,我看到过一些库在浮点控制字的设置上发生冲突,每个库都将其优先权强加于o其他。几乎和打印机驱动程序在程序提要下更改区域设置一样糟糕…@George:多好的回答!引用非常有趣。你是对的,我只想忽略它们。我会检查答案是否在我可接受的范围内,如果不在范围内,则抛出我自己的异常。这些标志值得了解。谢谢。@Peter Stewart:一个回答时要记住的重要一点是,如果结果是一个NaN(而不是一个数字),则比较运算符的工作方式与您认为的不同。例如,检测结果是否为NaN的一个简单方法是检查“f!=f”返回true。您可能还需要检查。请参见以下问题:谢谢。看起来我必须实现我自己的“throw”。这应该是批准的答案:它与原始问题相对应(接受的答案基本上是“你不应该麻烦”&第二个答案是“你不能”(这是不正确的)。