0

I've been struggling to find a crazy bug in some C++ code and narrowed it down to this small section. I placed into a simple main.c to debug it and can't figure out why the floating point math is rounding when it shouldn't.

// setup the variables for this simple case
int writep = 672;
float offset = 672.000122;
int bufferSize = 2400;
float bufferSizeF = (float)bufferSize;

float outPointer = (float)writep - offset;       // outPointer: -0.000122070313
if(outPointer < 0.0f){
    printf("outPointer: %.9f \n", outPointer);   // outPointer: -0.000122070313
    outPointer += bufferSizeF;                   // outPointer SHOULD be: 2399.9998779296875
    printf("outpointer: %.9f \n", outPointer);   // outPointer: 2400.000000000
}

Someone...please explain. Thanks.

pizzafilms
  • 3,829
  • 4
  • 24
  • 39
  • Maybe: http://stackoverflow.com/questions/588004/is-floating-point-math-broken – NathanOliver Oct 08 '16 at 21:12
  • 2
    Should you be using `double` rather than `float`? 2399.9998779296875 is exactly representable in IEEE 754 64-bit binary fp, but the closest 32-bit to it is 2400. – Patricia Shanahan Oct 08 '16 at 21:50
  • I didn't think that doubles would be needed. Refactoring now. – pizzafilms Oct 08 '16 at 21:56
  • Check FLT_EPSILON. Take the base 2 logarithm of 2400, and round up to get the magnitude. Then scale FLT_EPSILON by that. If greater than delta, 2400 += delta is a no-op and floating point unit is correct. – Malcolm McLean Oct 08 '16 at 21:59

2 Answers2

2

2400.000000000 and 2399.9998779296875 are too close for a standard float to differentiate them. Try this:

#include<iostream>
int main() {
    std::cout << (float)2399.9998779296875 << "\n";
}

It will probably give 2400 as output.

An IEEE 754 single precision float can only hold about 7 to 8 significant decimal digits. If you need a higher number of significant digits use a double precision double.

2

In IEEE 754 standard the floating point numbers are not equidistantly distributed over the number axis. Density of floating point values is higher around 0 than around 2400, so this is why the rounding is done when value is around 2400.

Here is the picture to illustrate it: https://www.google.fi/search?q=IEEE+754+distribution&biw=1920&bih=895&source=lnms&tbm=isch&sa=X&ved=0ahUKEwj-tKOWkMzPAhUEDywKHRdRAEUQ_AUIBigB#imgrc=rshe5_x1ZXFoKM%3A

igagis
  • 1,959
  • 1
  • 17
  • 27