首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SIGFPE诡计

SIGFPE诡计
EN

Stack Overflow用户
提问于 2014-02-04 14:04:16
回答 2查看 608关注 0票数 4

我重复了两次相同的计算,但是在一个中,我得到了一个浮点异常,而另一个没有。

代码语言:javascript
复制
#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++上测试了它,并得到了以下两个输出

代码语言:javascript
复制
y = 4.76299e-07
Floating point exception

到底怎么回事?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-02-04 14:42:09

问题在于

代码语言:javascript
复制
feenableexcept(-1);

这组FPE例外适用于所有可能的情况,包括不精确的结果(在浮点操作中非常常见)。您真的不应该在这里使用数字,而是使用提供的宏来设置您想要的位。

代用

代码语言:javascript
复制
feenableexcept(FE_INVALID   | 
               FE_DIVBYZERO | 
               FE_OVERFLOW  | 
               FE_UNDERFLOW);

帮我解决了这个问题。

什么时候

代码语言:javascript
复制
feenableexcept(FE_INVALID   | 
               FE_DIVBYZERO | 
               FE_OVERFLOW  | 
               FE_UNDERFLOW |
               FE_INEXACT);

是的,SIGFPE会回来的。这表明FE_INEXACT是问题的根源。

第一次计算没有给出SIGFPE的原因是,该除法已经在编译时完成(结果不准确)。在运行时,只执行乘法,这不会带来额外的不精确性。

票数 4
EN

Stack Overflow用户

发布于 2014-02-04 14:43:12

这是FE_INEXACT的例外。

这意味着x乘以编译时计算的常数1/(24.3*24.0*3600.0)不能在不损失精度的情况下转换为双倍。

第一个操作不会引发此异常,因为x是1.0,它具有精确的表示形式,并且在编译时常量已经转换为某种(不精确)的双重表示。

由于浮点异常处理不是标准化的,因此在其他编译器/平台上可能不会注意到这一点。

代码语言:javascript
复制
#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;
}

默认情况下,此异常显然是禁用的,否则根本无法执行任何浮点计算。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21554646

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档