Reputation: 2555
I try to multiply three number but I get a strange result. Why I get so different results?
unsigned int a = 7;
unsigned int b = 8;
double d1 = -2 * a * b;
double d2 = -2 * (double) a * (double) b;
double d3 = -2 * ( a * b );
// outputs:
// d1 = 4294967184.000000
// d2 = -112.000000
// d3 = 4294967184.000000
Upvotes: 2
Views: 6467
Reputation: 174
double is signed. Which means that the first bit (most significant bit aka sign bit) determines whether this number is positive or negative.
unsigned int cannot handle negative values because it uses the first bit (most significant bit) to expand the range of "positive" numbers it can express. so in
double d1 = -2 * a * b;
when executed, your machine puts the whole (-2 * a * b) in an unsigned int structure (like a and b) and it produces the following binary 1111 1111 1111 1111 1111 1111 1001 0000 (because it's the two's complement of 112 which is 0000 0000 0000 0000 0000 0000 0111 0000). But the problem here is that it's unsigned int so it's treated as a very big positive integer (which is 4294967184) because it doesn't treat the first 1 as a sign bit.
Then you put it in a double that's why you have the .00000 printed.
The other example, works because you typecast a to double and b to double so when multiplying -2 with a double, your computer will put it in a double structure, therefore, the sign bit will be considered.
double d3 = -2 * (double) (a * b)
will work as well.
To get a feeling about signed and unsigned, check this
Upvotes: 3
Reputation: 2294
In your first example, the number -2
is converted to unsigned int. The multiplication results in -112, which when represented as unsigned is 2^32 - 112 = 4294967184. Then this result is finally converted to double
for the assignment.
In the second example, all math is done on doubles, leading to the correct result. You will get the same result if you did:
double d3 = -2.0 * a * b
as -2.0
is a double
literal.
Upvotes: 10
Reputation: 300349
In C and C++ the built-in operators are always applied on two variables of the same type. A very precise set of rules guides the promotion of one (or two) of the two variables if they initially are different (or too small).
In this precise case, -2
is by default of type signed int
(synonym to int
) while a
and b
are of type unsigned int
. In this case, the rules state that -2
should be promoted to an unsigned int
, and because on your system you probably have 32 bits int
and a 2-complement representation, this ends up being 2**32 - 2
(4 294 967 294). This number is then multiplied by a
and the result taken modulo 2**32
(4 294 967 282), then b
, modulo 2**32
once again (4 294 967 184).
It's a weird system really, and has led to countless bugs. The overflow itself, for example, led to the Linux bug on June 30th this year which hanged up so many computers around the world. I hear it also crashed a couple Java systems.
Upvotes: 1
Reputation: 33126
double d1 = -2 * a * b;
Everything on the right hand side is an integral type, so the right hand side will be computed as an integral type. a
and b
are unsigned, so that dictates the specific type of the result. What about that -2
? It's converted to an unsigned int
. Negative integers are converted to unsigned integers using 2s complement arithmetic. That -2
becomes a very large positive unsigned integer.
double d2 = -2 * (double) a * (double) b;
Now the right hand side is mixed integers and floating point numbers, so the right hand side will be computed as a floating point type. What about that -2
? It's converted to a double. Now the conversion is straightforward: -2
converted to a double
becomes -2.0
.
Upvotes: 1