1

So I've basically got this code

#include <stdio.h>

int main()
{
    int n = 0x7fffffff;
    float f = n;

    printf("%d\n", n);
    printf("%f\n", f);

    n = 0x00ffffff;
    f = n;

    printf("%d\n", n);
    printf("%f", f);
}

This gives this output:

>     2147483647                                                                             
>     2147483648.000000                                                                      
>     16777215                                                                               
>     16777215.000000

Why the difference between the two first numbers, but not the second two numbers. I thought any integer can represented by any float in c. Why does this happen?

PEREZje
  • 2,272
  • 3
  • 9
  • 23
  • 8
    Not every number is representable as as `float`. First one is not. *any integer can represented by any float in c* - this is not true. `float` might be represented by the same number of bits as `int`, while it's range is much wider, including fractional numbers. So by [pigeonhole principle](https://en.wikipedia.org/wiki/Pigeonhole_principle) , it cannot represent all of the integers. – Eugene Sh. Sep 11 '18 at 20:36
  • 3
    "*I thought any integer can represented by any float in c*". Well now you know that is incorrect. Floats have limited precision. I recommend reading up on the IEEE 754 standard for specification of how floating point numbers work. https://en.wikipedia.org/wiki/IEEE_floating-point_standard – Christian Gibbons Sep 11 '18 at 20:36
  • 3
    Possible duplicate of [Representing integers in doubles](https://stackoverflow.com/questions/759201/representing-integers-in-doubles) – SergeyA Sep 11 '18 at 20:43
  • Integers are 32 bits, and floats are 32 bits for both mantissa and exponent. so by pidgeonhole principle alone there will be many integers not exactly representable as float. You can get all the 32-bit integers into a double. – Lee Daniel Crocker Sep 11 '18 at 21:29
  • @LeeDanielCrocker: "Integers are 32 bits, and floats are 32 bits " - That's not guaranteed and depends on the implementation. – too honest for this site Sep 11 '18 at 23:13
  • 1
    True, but it's probably the OP's case. – Lee Daniel Crocker Sep 11 '18 at 23:22
  • The bottom line here is "use doubles". Unless you really have a good reason to sacrifice precision, you'll find doubles to be the best choice. – rici Sep 12 '18 at 01:08

1 Answers1

10

Unfortunately, you thought wrong.

On a typical implementation with 32-bit ints and 32-bit floats, it is obvious that a float cannot contain all ints exactly, as some of its bits must be used for the exponent, to make it floating point.

If your platform is IEEE-754 compatible, and your float is single-precision, specifically it breaks up like this:

  • 1 bit - sign
  • 8 bits - exponent
  • 24 bits1 - significand

This means that all integers up to 24 bits can be exactly represented, after that, some precision must necessarily be lost for some numbers.

With the same assumptions, a double will hold all 32-bit integers, as a double has 53 bits of precision.

References:

1: Only 23 bits are stored, but the top bit is always considered to be 1, for regular numbers. This means if the top bit needs to be zero, the whole thing is shifted left, and the exponent decreased. This gets us an extra bit of precision that doesn't need to be stored.

Max
  • 10,701
  • 2
  • 24
  • 48
  • Thanks for the answer, confusion = gone. – PEREZje Sep 11 '18 at 20:43
  • Not entirely. Any size integer within `float` range can be exactly encoded as a 32-bit `float` provided that all its `1` bits are contained in a range of 24 bits. – Weather Vane Sep 11 '18 at 21:29
  • Well yes, there are some ints that can still be represented, but not all of them. Feel free to suggest an edit if you can put that eloquently. Edit: I changed the wording slightly to be more precise. – Max Sep 11 '18 at 21:34
  • So for example `uint64_t v = 0xFFFFFF0000000000;` can be exactly represented in `float`. – Weather Vane Sep 11 '18 at 21:36
  • For some extra fun, my question here might be interesting: https://stackoverflow.com/questions/25182556/rules-of-thumb-for-minimising-floating-point-errors-in-c – Ed King Sep 11 '18 at 21:42
  • 1
    In fact, although there are some `int`s that can be exactly represented as `float`s, they constitute less than one percent of all `int`s (32-bit / 32-bit case). It just happens that the ones that we most often care specifically about -- smallish ones, primarily -- are disproportionately among the representable ones. – John Bollinger Sep 11 '18 at 21:49