[英]How do I use try…catch to catch floating point errors?
我在visual studio express中使用c ++生成随机表达式树,用于遗传算法类型的程序。
因为它们是随机的,所以树通常会产生:除以零,溢出,下溢以及返回“inf”和其他字符串。 我可以为字符串编写处理程序,但文献让我对其他人感到困惑。 如果我理解正确,我必须先设置一些标志?
建议和/或指向一些文献的指针将不胜感激。 编辑:double变量中返回的值为1.#INF或-1。#IND。 我称他们为字符串是错误的。
根据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;
}
你确定要抓住它们而不是忽略它们吗? 假设你只是想忽略它们:
请参阅: 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/
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 ) {
// ...
}
从未尝试过,但假设除以零会引发异常,您可以将代码包装在try / catch中,如下所示:
尝试{//潜在除以零...} catch(...){// ...捕获所有异常}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.