noctilux
noctilux

Reputation: 803

Strange behaviour when comparing cast float to zero

I'm currently trying to learn about floating point representation in depth, so I played around a bit. While doing so, I stumbled on some strange behaviour; I can't really work out what's happening, and I'd be very grateful for some insight. Apologies if this has been answered, I found it quite hard to google!

#include <iostream>
#include <cmath>
using namespace std;

int main(){

  float minVal = pow(2,-149); // set to smallest float possible
  
  float nextCheck = static_cast<float>(minVal/2.0f); // divide by two
  bool isZero = (static_cast<float>(minVal/2.0f) == 0.0f); // this evaluates to false
  bool isZero2 = (nextCheck == 0.0f); // this evaluates to true
  cout << nextCheck << " " << isZero << " " << isZero2 << endl;
  // this outputs 0 0 1
  
  return 0;

}

Essentially what's happening is:

What's going on -- I would have thought them to be identical? Is the compiler trying to be clever, saying that dividing any number cannot possibly yield zero?

Thanks for your help!

Upvotes: 1

Views: 118

Answers (1)

Pascal Cuoq
Pascal Cuoq

Reputation: 80284

The reason isZero and isZero2 can evaluate to different values, and isZero can be false, is that the C++ compiler is allowed to implement intermediate floating-point operations with more precision than the type of the expression would indicate, but the extra precision has to be dropped on assignment.

Typically, when generating code for the 387 historical FPU, the generated instructions work on either the 80-bit extended-precision type, or, if the FPU is set to a 53-bit significand (e.g. on Windows), a strange floating-point type with 53-bit significands and 15-bit exponents.

Either way, minVal/2.0f is evaluated exactly because the exponent range allows to represent it, but assigning it to nextCheck rounds it to zero.

If you are using GCC, there is the additional problem that -fexcess-precision=standard has not yet been implemented for the C++ front-end, meaning that the code generated by g++ does not implement exactly what the standard recommends.

Upvotes: 5

Related Questions