The difference between ~ (x-1) and ~ x + 1 at x = 0x80000000

The language I use is C. Type x and n are int.

I have one line code as follows

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

This shows the value of x, n and two methods of shifting n bits of the complement number x. When x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000, but when these two are shifted by n bits, the results are different.

btw, if I changed 0xffffffff to ~ 1 + 1 (that means ~ (x + (~ 1 + 1)), the result will be the same as ~ x + 1

I wonder why this happened. Thanks.

+7
source share
3 answers

Now Pavan Manjunat's remote answer gave the correct answer for one case, assuming that int as usual a 32-bit type. Integer constant

 0xffffffff 

has a value of 2^32 - 1 and cannot be represented using int , but it is represented as unsigned int . Thus, its type is unsigned int (6.4.4.1). Therefore, x converted to unsigned int to be added, and

 ((~(x+0xffffffff))>>n) 

estimated as

 ((~(0x80000000u + 0xffffffffu)) >> n) ((~0x7fffffffu) >> n) (0x80000000u >> n) 

with a value of 2^(31-n) if 0 <= n < 32 (this is undefined behavior if n is outside this range).

Otherwise, ouah's answer is correct when x = 0x80000000 is int , ~0x8000000 = 0x7fffffff = INT_MAX and INT_MAX + 1 is undefined behavior in the form of integer overflow.

However, the general behavior is a wrapper, and then the result of the addition is an integer with the sign 0x80000000 , and the shift to the right of negative integers is the behavior determined by the implementation (6.5.7). Common shifts with the extension sign, which will give the result -2^(31-n) , which is then interpreted as unsigned int with the value 2^32 - 2^(31-n) the printf %x conversion specifier.

+4
source

When x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000,

On a system with a 32-bit int (assuming x is of type int ) and two padded signed views, this expression:

  ~x+1 

- undefined behavior. x = 0x80000000 means ~x == 0x7FFFFFFF == INT_MAX and INT_MAX + 1 undefined behavior. So ~x + 1 could be 0x80000000 or something else.

This expression:

 ~(x+0xffffffff) 

on the other hand it is defined ( 0xffffffff is unsigned int in C) and is equal to 0x80000000 . This is actually defined because 0xffffffff is an unsigned int , and unsigned int integers never overflow in the sense of the C standard.

This means that this statement:

 printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

causes undefined behavior, and it makes no sense to compare both results.

+1
source

(Assuming sizeof (int) is 4, i.e. a 32-bit signed value). 0x80000000; // - 2147483648, which is the smallest possible negative int 0xFFFFFFFF // - -1

Adding two together causes a "wrapping" from negative to positive 0x7FFFFFFF - this is the sum of two (using int arithmetic), which is 2147483647

Using the '~' operator on 0x7FFFFFFF gives a bitwise termination or 0x80000000

If you start with any int value and subtract 1 from it (or add 1 to it, it doesn't matter) enough time, you make it flip its sign. This is the main problem with arithmetic using fixed precision.

In your case, you cannot expect a mixture of signed arithmetic and bitwise operators without special attention to this limiting case.

Also note that when using 2-dimensional arithmetic, there is an asymmetry: there is one more negative number than a positive one (because you need to represent zero, which leaves an odd number of other bit representations for the rest of the values.)

0
source

All Articles