Search code examples
c++floating-pointieee-754floating-point-precisiondigits

Why float variable saves value by cutting digits after point in a weird way?


I have this simple code line:

float val = 123456.123456;

when i print this val or look in scope, it stores value 123456.13

Ok, it's fine, it can't store all those digits after point just in 4 bytes, but why does it make 13 after the point? Shouldn't it be 12?

(using vc++ 2010 express on win32)


Solution

  • When represented as a float, your number has an exponent of 16 (i.e. the value is its mantisse times 2^16, or 65536). The mantisse then becomes

    123456.123456 / 65536 = 1.8837909462890625
    

    In order to fit in a 32-bit float, the mantisse is truncated to 23 bits, so now it becomes 1.883791. When multiplied back by 65536, it becomes 123456.125.

    Note the 5 in the third position after the decimal point: the output routine of C++ that you used rounds it up, making your final number look like 123456.13.

    EDIT Explanation of the rounding: (Rick Regan's comment)

    The rounding occurs first in binary (to 24 bits), in decimal to binary conversion, and then to decimal, in printf. The stored value is 1.1110001001000000001 x 2^16 = 1.8837909698486328125 x 2^16 = 123456.125. It prints as 123456.13, but only because Visual C++ uses "round half away from zero" rounding.

    Rick has an outstanding article on the subject, too.

    If you would like to play with other numbers and their float representations, here is a very useful IEEE-754 calculator.