user2584960
user2584960

Reputation: 695

C# Weird division issue

I have one int and one uint type:

int tempA = 0xbc000669;
uint tempB = 0xbc000669;

when I do

tempA /0x2000, wanting to shift to the right by 13, it gives me 0xfffde001

while

tempB / 0x2000, wanting also to shift to the right by 13, it gives me the correct answer: 0x0005e000

anybody knows why with a signed division, I get a false answer? I didn't think division could overflow? Thanks

Upvotes: 0

Views: 222

Answers (4)

helb
helb

Reputation: 7793

In the statement

tempA / 0x2000

the compiler sees a variable of type int and a numeric literal value. Since division on type int requires two operands of type int, the value 0x2000 is automatically cast to int as well. The statement evaluates to

(int)0xbc000669 / (int)0x2000

which is -1140849047 / 8192 and equals to -139263

-139263 in hex is FFFDE001 (on 32 bit values at least)

Upvotes: 4

King King
King King

Reputation: 63377

0xbc000669 in fact can't be contained in an int, more exactly it will represent a negative integer. We know that an int uses the 32nd bit as the sign bit. While 0cbc000669 has the most significant nibble as 0xb which is equal to 1011 -> the 32nd bit is 1 and the actual integer is negative. So:

int tempA = 0xbc000669;

will make tempA equal to -1140849047, right-shifting this number 13 binary digits will return the exact result you get: 0xfffde001.

if you declare your tempB as uint like this:

uint tempB = 0xbc000669;

it can be contained totally in a uint because uint doesn't use the 32nd bit as the sign bit. The actual number is a positive integer and its value is 3154118249, right-shifting this value 13 binary digits will give you the exact result as 0x5e000

Upvotes: 1

Shaz
Shaz

Reputation: 1396

The best way to explain this is to show how the bits work out. The Wikipedia article on signed number representation covers it well. You'll want to read the the section on Two's complement.

The expectation, I think, is that people want the binary of -1 and 1 to be the same, with the exception that the sign bit is 1 for -1. This is not the case. 1, for example, is

0000 0000 0000 0000 0000 0000 0000 0001

And -1 is

1111 1111 1111 1111 1111 1111 1111 1111

What people would intuitively think is -1 is actually -127:

-127 == 1000 0000 0000 0000 0000 0000 0000 0001

So now let's look at the the answers you got. In signed division, when you shift to the right, you actually end up padding the left side of your number with 1s, and adding 1. And that's exactly what you see with your results.

0xFFFDE001 = 1111 1111 1111 1101 1110 0000 0000 0001
0x0005E000 = 0000 0000 0000 0101 1110 0000 0000 0000

As you'll notice, they're both the same, except the top one(from your signed division) has 13 1's padded on the left, and an added 1 at the end.

The important thing to remember with signed integers is that two's complement changes the ordering of bits, so, excluding the sign bit, -50 does not have the same bit pattern as +50.

Upvotes: 0

David W
David W

Reputation: 10184

From the blurb in the spec about integer division:

The division rounds the result towards zero, and the absolute value of the result is the largest possible integer that is less than the absolute value of the quotient of the two operands. The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs.

If I interpret that text correctly, it leads to this: In the first example, the signed int value has the sign bit set; the second number (0x2000) is positive, thus the result is either zero or negative.

Upvotes: 0

Related Questions