我正在重复相同的计算两次,但在一次中我得到一个浮点异常,而在另一次我得不到。
#include <iostream>
#include <cmath>
#include <fenv.h>
using namespace std;
int main(void)
{
feenableexcept(-1);
double x,y,z;
x = 1.0;
y = (1.0/(24.3*24.0*3600.0))*x;
cout << "y = " << y << endl;
z = x/(24.3*24.0*3600.0);
cout << "z = " << z << endl;
return 0;
}
我在g ++和clang ++上测试了它,并在
中得到了以下输出y = 4.76299e-07
Floating point exception
发生了什么事?
答案 0 :(得分:5)
这是FE_INEXACT例外
这意味着x
乘以在编译时计算的常量1/(24.3*24.0*3600.0)
,不能在不损失精度的情况下转换为double。
第一个操作不会引发此异常,因为x
是1.0,它具有精确的表示形式,并且该常量在编译时已经转换为某个(不精确的)双重表示。
由于浮点异常处理未标准化,因此在其他编译器/平台上可能不会注意到这一点。
#include <iostream>
#include <cmath>
#include <fenv.h>
using namespace std;
int main(void)
{
feenableexcept(FE_INEXACT); // comment this line out and the exception is gone
double x,y,z;
x = 1.0;
y = (1.0/(24.3*24.0*3600.0))*x;
cout << "y = " << y << endl;
z = x/(24.3*24.0*3600.0); // <-- FE_INEXACT exception
cout << "z = " << z << endl;
return 0;
}
默认情况下,此异常显然已禁用,否则您根本无法进行任何浮点计算。
答案 1 :(得分:4)
问题在于
feenableexcept(-1);
对于所有可能的情况,这组FPE exceptions包括不精确的结果(在浮点运算中非常常见)。你真的不应该在这里使用数字,而是使用提供的宏来设置你想要的位数。
替换
feenableexcept(FE_INVALID |
FE_DIVBYZERO |
FE_OVERFLOW |
FE_UNDERFLOW);
为我解决了这个问题。
当
feenableexcept(FE_INVALID |
FE_DIVBYZERO |
FE_OVERFLOW |
FE_UNDERFLOW |
FE_INEXACT);
,SIGFPE将返回。这表明FE_INEXACT是问题的根本原因。
第一次计算没有给出SIGFPE的原因是除法已经在编译时完成(结果不准确)。在运行时,仅执行乘法,这不会引入额外的不精确性。