What does this ">>=" operator mean in C? - c

unsigned long set;
/*set is after modified*/
set >>= 1;
I found this in a kernel system call but I don't understand, how does it work?

The expression set >>= 1; means set = set >> 1; that is right shift bits of set by 1 (self assigned form of >> bitwise right shift operator check Bitwise Shift Operators).
Suppose if set is:
BIT NUMBER 31 n=27 m=17 0
▼ ▼ ▼ ▼
set = 0000 1111 1111 1110 0000 0000 0000 0000
Then after set >> = 1; variable set becomes:
BIT NUMBER 31 n=26 m=16 0
▼ ▼ ▼ ▼
set = 0000 0111 1111 1111 0000 0000 0000 0000
Notice the bits number shifted.
Note a interesting point: Because set is unsigned long so this >> operation should be logical shift( unsigned shift) a logical shift does not preserve a number's sign bit.
Additionally, because you are shifting all bits to right (towards lower significant number) so one right shift is = divide number by two.
check this code (just to demonstrate last point):
int main(){
unsigned long set = 268304384UL;
set >>= 1;
printf(" set :%lu \n", set);
set = 268304384UL;
set /= 2;
printf(" set :%lu \n", set);
return 1;
}
And output:
set :134152192
set :134152192
(note: its doesn't means >> and / are both same)
Similarly you have operator <<= for left shift, check other available Bitwise operators and Compound assignment operators, also check section: bit expressions and difference between: signed/arithmetic shift and unsigned shift.

This "right-shift"s the value by one bit. If you move all the bits of an integer to the right by 1 then you effectively "divide by 2" because binary is a base-2 numbering system.
Imagine you have the number 12 in binary:
1100 = 12 in binary
110 = 6 in binary (1100 right-shifted)
Just like if you moved all of the digits in a base-10 number right by one you would be dividing by 10.

Every binary operator can be combined with =. In all cases
dest op= expression
is equivalent to
dest = dest op expression
(except if dest has any side effects, they only take place once).
So this means that
set>>=1;
is equivalent to:
set = set >> 1;
Since >> is the binary right-shift operator, it means to shift the value in set right by 1 bit.

This shifts bit to the right by 1 which is equivalent to division by 2. For more information on bit shifting, refer to http://msdn.microsoft.com/en-us/library/f96c63ed(v=vs.80).aspx

The above command performs right shift by one bit .Refer bit wise operations in c from this link http://www.cprogramming.com/tutorial/bitwise_operators.html

Related

Trying to perform bitwise operation on a negative number to make 0s in bits 31-16 (32 bit number) in C

I have a number, -3, that I would like to use as a 16 bit integer and use an | (or) operator with a 32 bit integer.
So ideally, I need it so that -3, in binary two's complement, will be 0000 0000 0000 0000 1111 1111 1111 1101
I've tried bit wise operation using
int x = -3;
x = x << 16;
x = x >> 16;
I thought this would ideally put 0's in the bits 31-16 (0 indexed), but it doesn't seem to work. Any help to achieve this would be appreciated.
Two ways to get the two’s complement of 3 in 16 bits, with higher bits clear, are:
Include <stdint.h> and use (uint16_t) -3.
Use -3u & 0xffffu.
Shifting a negative value to the left is undefined behavior.
int x = -3;
x = x << 16; // UB!
Shifting a negative value to the right is implementation-defined behavior.
Best to use unsigned type (or small postive values) when shifting.
to perform bitwise operation on a negative number to make 0s in bits 31-16 (32 bit number) i
Use & to mask and retain only the least significant 16 bits.
int32_t x = -3;
x &= 0xFFFF;

Diffrent usage of &- operator

Look at the following code:
#include <stdio.h>
int main()
{
int num, sum;
scanf("%d", &num);
sum = num - (num&-num);
printf("%d", sum);
return 0;
}
The line sum = num - (num& - num) returns value of the given number without the last 1 in binary format. For example if the num is equal to 6(110) it will give the value without the last 1. In this case 100 which is equal to 4.
My question is how does &- work and how could do we do the same thing in octal numeral system?
What you have here is two separate operators: the bitwise AND operator & and the unary negation operator -. So the line in question is actually:
sum = num - (num & -num);
Assuming integers are stored in two's complement representation, negating a value means inverting all bits and adding one.
In the case that num is 6, (binary 00000110), -num is -6 which is 11111010. Then performing a bitwise AND between these two values results in 00000010 in binary which is 2 in decimal, so num - (num & -num) is 6 - 2 which is 4.
There is no &- operator. num - (num&-num) is num - (num & -num), where & performs the bitwise AND of num and its negation, -num.
Consider some number in binary, say 0011 0011 1100 11002 (spaces used for easy visualization). The negative of this is −0011 0011 1100 11002. However, we commonly represent negative numbers using two’s complement, in which a power of two is added. For 16-bit formats, we add 216, which is 1 0000 0000 0000 00002. So, to represent −0011 0011 1100 11002, we use 1 0000 0000 0000 00002 + −0011 0011 1100 11002 = 1100 1100 0011 01002.
Observe what happens in this subtraction, column by column from the right:
In the rightmost column, we have 0−0, which yields 0.
The next column also has 0−0, yielding 0.
The next column has 0−1. This yields 1 with a borrow from the column to the left.
The next column has 0−1−1 (where the second −1 is the borrow). This yields 0 with another borrow.
Because the minuend (the number being subtracted from) has all zeros up to that initial 1, this borrow is never satisfied, so it propagates throughout the bits.
Thus the result is:
Starting at the right, 0s remain 0s.
The first 1 stays a 1 but starts a borrow chain.
Because of the borrow, all bits to the left of that flip from 0 to 1 or 1 to 0.
Thus the subtrahend (the number being subtracted) and the result differ in all bits to the left of the first 1. And they both have 0s to the right of the first 1. So the only bit they both have set is that first 1.
Therefore, when two’s complement is in use, the result of num & -num is the lowest 1 bit that is set in num.
Then num - (num & -num) subtracts this bit from num, leaving it as num with its lowest 1 bit changed to 0.

Can someone explains why this works to count set bits in an unsigned integer?

I saw this code called "Counting bits set, Brian Kernighan's way". I am puzzled as to how "bitwise and'ing" an integer with its decrement works to count set bits, can someone explain this?
unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
v &= v - 1; // clear the least significant bit set
}
Walkthrough
Let's walk through the loop with an example : let's set v = 42 which is 0010 1010 in binary.
First iteration: c=0, v=42 (0010 1010).
Now v-1 is 41 which is 0010 1001 in binary.
Let's compute v & v-1:
0010 1010
& 0010 1001
.........
0010 1000
Now v&v-1's value is 0010 1000 in binary or 40 in decimal. This value is stored into v.
Second iteration : c=1, v=40 (0010 1000). Now v-1 is 39 which is 0010 0111 in binary. Let's compute v & v-1:
0010 1000
& 0010 0111
.........
0010 0000
Now v&v-1's value is 0010 0000 which is 32 in decimal. This value is stored into v.
Third iteration :c=2, v=32 (0010 0000). Now v-1 is 31 which is 0001 1111 in binary. Let's compute v & v-1:
0010 0000
& 0001 1111
.........
0000 0000
Now v&v-1's value is 0.
Fourth iteration : c=3, v=0. The loop terminates. c contains 3 which is the number of bits set in 42.
Why it works
You can see that the binary representation of v-1 sets the least significant bit or LSB (i.e. the rightmost bit that is a 1) from 1 to 0 and all the bits right of the LSB from 0 to 1.
When you do a bitwise AND between v and v-1, the bits left from the LSB are the same in v and v-1 so the bitwise AND will leave them unchanged. All bits right of the LSB (including the LSB itself) are different and so the resulting bits will be 0.
In our original example of v=42 (0010 1010) the LSB is the second bit from the right. You can see that v-1 has the same bits as 42 except the last two : the 0 became a 1 and the 1 became a 0.
Similarly for v=40 (0010 1000) the LSB is the fourth bit from the right. When computing v-1 (0010 0111) you can see that the left four bits remain unchanged while the right four bits became inverted (zeroes became ones and ones became zeroes).
The effect of v = v & v-1 is therefore to set the least significant bit of v to 0 and leave the rest unchanged. When all bits have been cleared this way, v is 0 and we have counted all bits.
Each time though the loop one bit is counted, and one bit is cleared (set to zero).
How this works is: when you subtract one from a number you change the least significant one bit to a zero, and the even less significant bits to one -- though that doesn't matter. It doesn't matter because they are zero in the values you're decrementing, so they will be zero after the and-operation anyway.
XXX1 => XXX0
XX10 => XX01
X100 => X011
etc.
Let A=an-1an-2...a1a0 be the number on which we want to count bits and k the index of the right most bit at one.
Hence A=an-1an-2...ak+1100...0=Ak+2k where Ak=an-1an-2...ak+1000...0
As 2k−1=000..0111..11, we have
A-1=Ak+2k-1=an-1an-2...ak+1011...11
Now perform the bitwise & of A and A-1
an-1an-2...ak+1100...0 A
an-1an-2...ak+1011...1 A-1
an-1an-2...ak+1000...0 A&A-1=Ak
So A&A-1 is identical to A, except that its right most bit has been cleared, that proves the validity of the method.

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
e.g.
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

How to set and clear bits without ~ operator

I am using a C like script for Bluegiga chip and their scripting langauge does not have the ~ operator in the compiler.
Is there any way to work with bits using pure math?
For example i read a byte and i need to clear bit 1 and set bit 2.
The following bitwise operations are supported:
Operation Symbol
AND &
OR |
XOR ^
Shift left <<
Shift right >>
The following mathematical operators are supported:
Operation Symbol
Addition: +
Subtraction: -
Multiplication: *
Division: /
Less than: <
Less than or equal: <=
Greater than: >
Greater than or equal: >=
Equals: =
Not equals: !=
Just use OR and AND operations. To do that operation:
initial byte: 0000 0001
clear bit 1: 0000 0001 & 1111 1110 --> result - 0000 0000 (The 1st bit of the second operand must be 0 to clear the bit)
now set bit 2: 0000 0000 | 0000 0010 --> result - 0000 0010 (The 2st bit of the second operand must be 1 to set the bit)
Note that for this operations you only change the specific bit all the other remain with the same value.
Also to obtain the second operand you can just obtain it by:
for the set operation on the n bit - the second operand is 2^n
for the clear operation on the n bit - the second operand is 1111 1111 XOR 2^n (in this case 1111 1111 XOR is used for the not operation).
If you are missing the ~ operator, you can make your own using XOR and a constant.
#include<stdio.h>
int main()
{
unsigned int s = 0xFFFFFFFF ;
printf("%#x" , 0xFF ^ s ) ; //XOR with the constant is equivalent to ~
unsigned int byte = 0x4 ;
printf("%#x" , 0x5 & ( byte ^ s ) ) ; //clear those bits
return 0 ;
}
When you have ~ it is easy to clear the bits.
Clearing a (single) bit is also equivalent to SET following by INVERT (or xor). Thus.
aabbccdd <-- original value
00000110 OR
00000010 XOR
--------
aabbc10d <-- result (I'm counting the bits from 7 downto 0)
This approach has the benefit of being scalable from byte to the native integer size without the burden of calculating the mask for AND operation.
Performing a XOR against -1 will invert all the bits in an integer.

Resources