سؤال

I'm repeating the same calculation twice, but in one I get a floating point exception while in the other I don't.

#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;
}

I tested it on both g++ and clang++ and got the following output in both

y = 4.76299e-07
Floating point exception

What's going on?

هل كانت مفيدة؟

المحلول 2

The problem is with

feenableexcept(-1);

This sets of FPE exceptions for all possible cases, include inexact results (which are very common in floating point operations). You really shouldn't be using a number here but instead use the provided macros to set the bits you want.

Replacing by

feenableexcept(FE_INVALID   | 
               FE_DIVBYZERO | 
               FE_OVERFLOW  | 
               FE_UNDERFLOW);

resolves the problem for me.

When

feenableexcept(FE_INVALID   | 
               FE_DIVBYZERO | 
               FE_OVERFLOW  | 
               FE_UNDERFLOW |
               FE_INEXACT);

is given, the SIGFPE will return. This shows that FE_INEXACT is the root cause of the problem.

The reason that the first calculation is not giving SIGFPE is that the division is already done at compile time (with inexact results). At runtime only multiplication is performed, which does not introduce additional inexactness.

نصائح أخرى

That's the FE_INEXACT exception.
It means x multiplied by the constant 1/(24.3*24.0*3600.0) computed at compile time cannot be converted to double without loss of precision.

The first operation does not raise this exception because x is 1.0, which has an exact representation, and the constant has already been converted to some (inexact) double representation at compile time.

Since floating point exceptions handling is not standardized, this might go unnoticed on other compilers/platforms.

#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;
}

This exception is obviously disabled by default, or else you could hardly do any floating point computation at all.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top