4

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?

user2535797
  • 529
  • 3
  • 10
  • 2
    What platform/compiler? (It's fine here, for instance: http://ideone.com/SYmWam) – Oliver Charlesworth Feb 04 '14 at 14:08
  • 2
    My guess is that in the former calculation division is done at compile time, leaving only multiplication. In the latter case, the division is done at runtime. Is the compiler using different arithmetic? Are you cross-compiling? – DeltaLima Feb 04 '14 at 14:17
  • without the statement `feenableexcept(-1);` it is working fine. feel something to do with the function. i m not aware of what it is doing:( – Sakthi Kumar Feb 04 '14 at 14:25
  • Read [FPE_FLTOVF_TRAP](http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_21.html#SEC358) – Grijesh Chauhan Feb 04 '14 at 14:26

2 Answers2

5

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.

kuroi neko
  • 8,479
  • 1
  • 19
  • 43
4

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.

DeltaLima
  • 5,864
  • 1
  • 16
  • 32
  • thanks for the credits, Mr DL. Feel free to copy the sample code too, it's not copyrighted :). – kuroi neko Feb 04 '14 at 14:55
  • @kuroineko if you look at the comments under the original question, you see that I am just including my earlier remarks. Thank you for your credits KN. – DeltaLima Feb 04 '14 at 14:57