简体   繁体   中英

Minus operator used as unary bitwise operation

I don't fully understand how the "-" operator affects the following code:

#define COMP(x) ((x) & -(x))

unsigned short a = 0xA55A;
unsigned short b = 0x0400;

Could someone explain what COMP(a) and COMP(b) are and how they are calculated?

(x) & -(x) is equal to the lowest bit set in x when using 2's complement for representing binary numbers.

This means COMP(a) == 0x0002; and COMP(b) == 0x0400;

the "-" sign negative the value of the short parameter in a two's complement way. (in short, turn all 0 to 1, 1 to 0 and then add 1)

so 0xA55A in binary is 1010 0101 0101 1010
then -(0xA55A) in binary is 0101 1010 1010 0110
run & between them will give you 0000 0000 0000 0010

-(x) negates x . Negation in two's complement is the same as ~x+1 (bitflip+1) as the code below shows:

#include <stdio.h>
#include <stdio.h>
#include <stdint.h>
int prbits(uintmax_t X, int N /*how many bits to print (from the low end)*/)
{
    int n=0;
    uintmax_t shift=(uintmax_t)1<<(N-1);
    for(;shift;n++,shift>>=1) putchar( (X&shift)?'1':'0');
    return n;
}
int main()
{
    prbits(0xA55A,16),puts("");
    //1010010101011010

    prbits(~0xA55A,16),puts("");
    //0101101010100101

    prbits(~0xA55A+1,16),puts("");
    //0101101010100110
    prbits(-0xA55A,16),puts("");
    //0101101010100110 (same)

}

When you bitand a value with its bitfliped value, you get 0. When you bitand a value with its bitfliped value + 1 (=its negated value) you get the first nonzero bit from the right.

Why? If the rightmost bit of ~x is 1, adding 1 to it will yield 0 with carry=1 . You repeat this while the rightmost bits are 1 and, zeroing those bits. Once you hit zero (which would be 1 in x , since you're adding 1 to ~x ), it gets turned into 1 with carry==0, so the addition ends. To the right you have zeros, to the left you have bitflips. You bitand this with the original and you get the first nonzero bit from the right.

Basically, what COMP does is AND the two operands of which one is in its original form and one of which is a negation of it's form.

How CPUs typically handle signed numbers is using 2's Complement , 2's complement splits the range of a numeric data type to 2, of which (2^n-1) -1 is positive and (2^n-1) is negative.

The MSB (right-most bit) represents the sign of the numeric data

eg

0111 -> +7
0110 -> +6
0000 -> +0
1111 -> -1
1110 -> -2
1100 -> -6

So what COMP does by doing an AND on positive and negative version of the numeric data is to get the LSB (Left-most bit) of the first 1.

I wrote some sample code that can help you understand here: http://coliru.stacked-crooked.com/a/935c3452b31ba76c

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM