Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

int divided by unsigned int causing rollover

I try to divide int by unsigned int and I get unexpected result:

int b;
unsigned int c;
int res;
float res_f;

b = -25;
c = 5;

res = b / c;   // res = 858993454
res_f = b / c; // res_f = -5.000000

The same works just fine for '+', '-' and '*', but fails for '/'. What is it that I miss here?

P.S.

It was tested on different compilers and the result was the same.

like image 522
shushu Avatar asked Mar 16 '11 16:03

shushu


People also ask

What happens when you cast an int to an unsigned int?

You can convert an int to an unsigned int . The conversion is valid and well-defined. Since the value is negative, UINT_MAX + 1 is added to it so that the value is a valid unsigned quantity. (Technically, 2N is added to it, where N is the number of bits used to represent the unsigned type.)

What happens when unsigned int overflows?

"A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type."

What happens when you subtract an unsigned int from a signed int?

An int is signed by default, meaning it can represent both positive and negative values. An unsigned is an integer that can never be negative. If you take an unsigned 0 and subtract 1 from it, the result wraps around, leaving a very large number (2^32-1 with the typical 32-bit integer size).

What happens if you try to make an unsigned int negative?

You simply cannot assign a negative value to an object of an unsigned type. Any such value will be converted to the unsigned type before it's assigned, and the result will always be >= 0.


1 Answers

Assuming this is C or similar (e.g. Objective C), change:

res = b / c;

to:

res = b / (int)c;

Explanation: b is being converted from int to unsigned int, according to C's type conversion rules for mixed expressions. In the process it overflows from -25 to 0xFFFFFFE7 == 4294967271. Then you get an unsigned int result of 4294967271 / 5U = 858993454U, which is then being implicitly converted back to an int (no overflow in this step, as the result is in the range of both signed and unsigned 32-bit ints).

By the way, the float result should be the same, within the precision limits of a float (I get 858993472.0). I'm surprised that you get -5.0 in this case.

like image 106
Paul R Avatar answered Oct 28 '22 07:10

Paul R