I was working on an embedded project when I ran into something which I thought was strange behaviour. I managed to reproduce it on codepad (see below) to confirm, but don't have any other C compilers on my machine to try it on them.
Scenario: I have a #define
for the most negative value a 32-bit integer can hold, and then I try to use this to compare with a floating point value as shown below:
#define INT32_MIN (-2147483648L)
void main()
{
float myNumber = 0.0f;
if(myNumber > INT32_MIN)
{
printf("Everything is OK");
}
else
{
printf("The universe is broken!!");
}
}
Codepad link: http://codepad.org/cBneMZL5
To me it looks as though this this code should work fine, but to my surprise it prints out The universe is broken!!
.
This code implicitly casts the INT32_MIN
to a float
, but it turns out that this results in a floating point value of 2147483648.0
(positive!), even though the floating point type is perfectly capable of representing -2147483648.0
.
Does anyone have any insights into the cause of this behaviour?
CODE SOLUTION: As Steve Jessop mentioned in his answer, limits.h
and stdint.h
contain correct (working) int
range define
s already, so I'm now using these instead of my own #define
PROBLEM/SOLUTION EXPLANATION SUMMARY: Given the answers and discussions, I think this is a good summary of what's going on (note: still read the answers/comments because they provide a more detailed explanation):
long
s, so any values greater than LONG_MAX
and less or equal to ULONG_MAX
followed by the L
postfix have a type of unsigned long
(-2147483648L)
is actually a unary -
on an unsigned long
(see previous point) value: -(2147483648L)
. This negation operation 'wraps' the value around to be the unsigned long
value of 2147483648
(because 32-bit unsigned long
s have the range 0
- 4294967295
).unsigned long
number looks like the expected negative int
value when it gets printed as an int
or passed to a function because it is first getting cast to an int
, which is wrapping this out-of-range 2147483648
around to -2147483648
(because 32-bit int
s have the range -2147483648 to 2147483647)float
, however, is using the actual unsigned long
value 2147483648
for conversion, resulting in the floating-point value of 2147483648.0
.A signed 32-bit integer variable has a maximum value of 231 − 1 = 2,147,483,647, whereas an IEEE 754 32-bit base-2 floating-point variable has a maximum value of (2 − 2−23) × 2127 ≈ 3.4028235 × 1038.
float is a 32-bit IEEE 754 single precision Floating Point Number – 1 bit for the sign, 8 bits for the exponent, and 23* for the value.
Float is a 32-bit data type representing the single precision floating-point format, in IEEE 754-1985 called single, in IEEE 754-2008 the 32-bit base 2 format is officially referred to as binary32.
Replace
#define INT32_MIN (-2147483648L)
with
#define INT32_MIN (-2147483647 - 1)
-2147483648
is interpreted by the compiler to be the negation of 2147483648
, which causes overflow on an int
. So you should write (-2147483647 - 1)
instead.
This is all C89
standard though. See Steve Jessop's answer for C99
.
Also long
is typically 32 bits on 32-bit machines, and 64 bits on 64-bit machines. int
here gets the things done.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With