Convert INT_MAX to float and then back to integer.

In C programming, I find a strange problem that takes into account my intuition. When I declare integer as INT_MAX ( 2147483647 defined in limit.h) and implicitly convert it to float value, it works fine, i.e. The float value matches the maximum integer, And then, I convert the float back to an integer, something interesting happens. The new integer becomes the minimum integer ( -2147483648 ).
The source codes are as follows:

 int a = INT_MAX; float b = a; // b is correct int a_new = b; // a_new becomes INT_MIN 

I'm not sure what will happen when the floating-point number b is converted to the integer a_new . So, is there a reasonable solution to find the maximum value that can be switched back and forth between the integer and float types?

PS: value INT_MAX - 100 works fine, but this is just an arbitrary workaround.

+8
c type-conversion integer-overflow
source share
1 answer

This answer assumes that the float is an IEEE-754 single-point float encoded as 32-bit, and int is 32-bit. See this Wikipedia article for more information on IEEE-754.


Floating-point numbers have only 24-bit precision, compared to 32 bits for int. Therefore, int values ​​from 0 to 16777215 have an exact representation in the form of floating-point numbers, but numbers larger than 16777215 do not necessarily have exact representations as a float. The following code demonstrates this fact (on systems using IEEE-754).

 for ( int a = 16777210; a < 16777224; a++ ) { float b = a; int c = b; printf( "a=%dc=%db=0x%08x\n", a, c, *((int*)&b) ); } 

Expected Result:

 a=16777210 c=16777210 b=0x4b7ffffa a=16777211 c=16777211 b=0x4b7ffffb a=16777212 c=16777212 b=0x4b7ffffc a=16777213 c=16777213 b=0x4b7ffffd a=16777214 c=16777214 b=0x4b7ffffe a=16777215 c=16777215 b=0x4b7fffff a=16777216 c=16777216 b=0x4b800000 a=16777217 c=16777216 b=0x4b800000 a=16777218 c=16777218 b=0x4b800001 a=16777219 c=16777220 b=0x4b800002 a=16777220 c=16777220 b=0x4b800002 a=16777221 c=16777220 b=0x4b800002 a=16777222 c=16777222 b=0x4b800003 a=16777223 c=16777224 b=0x4b800004 

Interestingly, the float value 0x4b800002 is used to represent the three int values ​​16777219, 16777220 and 16777221, and thus converting 16777219 to float and vice versa to int does not preserve the exact value of int .


The two floating point values ​​that are closest to INT_MAX are 2147483520 and 2147483648, which can be demonstrated with this code

 for ( int a = 2147483520; a < 2147483647; a++ ) { float b = a; int c = b; printf( "a=%dc=%db=0x%08x\n", a, c, *((int*)&b) ); } 

The interesting parts of the output are

 a=2147483520 c=2147483520 b=0x4effffff a=2147483521 c=2147483520 b=0x4effffff ... a=2147483582 c=2147483520 b=0x4effffff a=2147483583 c=2147483520 b=0x4effffff a=2147483584 c=-2147483648 b=0x4f000000 a=2147483585 c=-2147483648 b=0x4f000000 ... a=2147483645 c=-2147483648 b=0x4f000000 a=2147483646 c=-2147483648 b=0x4f000000 

Note that all 32-bit int values ​​from 2147483584 to 2147483647 will be rounded to a float value of 2147483648. The largest int value that will be rounded down is 2147483583, which is the same as (INT_MAX - 64) on a 32-bit system.

Thus, we can conclude that the numbers below (INT_MAX - 64) will safely convert from int to float and back to int . But this is true only in systems where the int size is 32 bits, and encoded.

+10
source share

All Articles