Diffrent usage of &- operator - c

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.

Related

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

generating numbers using a n-bit number (similar to generating subsets of n-bit value)

Given a number 'n' and the corresponding binary value. I want to generate all combinations of n, using only the bits set in 'n'.
for example: if n=11 and its binary representation 1011, the combinations are:
0000
0001
0010
0011
1000
1001
1010
1011
example 2: if n=49 and its binary representation is 11001, the combinations are:
00000
00001
01000
01001
10000
10001
11000
11001
The easiest way could be to write a C subroutine to generate these combinations, however, i need some efficient way/algorithm for generating these combinations (some bit manipulation techniques similar to bit twiddling hacks).
Thanks.
Here's an illustration of a technique using simple bit twiddling. It uses the guaranteed semantics of binary arithmetic on unsigned values.
In the expression i = n & (i - n) below, all the sub-expressions, i, n, (i - n) and n & (i - n) are the same type, unsigned int and are unaffected by the integer promotion rules. Mathematically, the sub-expression (i - n) is evaluated modulo 2m, where 2m - 1 is the maximum value that can be represented by an unsigned int.
#include <stdio.h>
int main(void)
{
unsigned int n = 49;
unsigned int i;
for (i = 0; ; i = n & (i - n)) {
printf("%u", i);
if (i == n)
break;
putchar(' ');
}
putchar('\n');
return 0;
}
Example step
Assuming n is 49, or 0000000000110001₂, and the current value of i is 16, or 0000000000010000₂. Then for 16-bit, 2's complement arithmetic, we have:
0000000000010000₂
0000000000110001₂ -
----------------
1111111111011111₂
0000000000110001₂ &
----------------
0000000000010001₂ (= 17)
This is vaguely similar to the well-known technique to find the lowest '1' bit in an unsigned value x as x & -x, which works because ANDing a number with its two's complement leaves only the lowest '1' bit set in the result.
Get the binary string for your number.
Create a tree node labeled Z.
Let node := Z.
Let N := 1.
Read symbol N of your string (from the left, 1-indexed)
If symbol is 1, add two children of node; label the first child with node's label + 1, the other with node's label + 0. If symbol is 0, add one child of node; label the child with node's label + 0.
Increment the value of N.
Repeat steps 5 - 7 for all children of node, recursively, until in step 7 you increment the value of N to a value larger than the length of your original binary string. That condition terminates the recursion.
Once the tree has been so constructed, the leaves of the tree are labeled with your allowed values. Any tree traversal mechanism which visits the leaves will allow you to recover the allowed binary strings.
Iterating integers through only certain allowed bits? How about this function:
int NextMasked (int val, int mask) {
return ((val | ~mask) + 1) & mask;
}
Function step by step:
take previous value val and set all the bits to 1, which are NOT set in the mask
increment resulting value by 1
now; clear all bits what we set earlier, only allowing same bits what are set in the mask
tada.wav; we have new value and we going to return it to caller.
Let's test this with your example (mask = 11 and initially val = 0):
Here all values are in binary:
val = 0000, mask = 1011, ~mask = 0100 (bits inverted)
(old) (new)
val |~mask +1 &mask
0000 0100 0101 0001
0001 0101 0110 0010
0010 0110 0111 0011
0011 0111 1000 1000
1000 1100 1101 1001
1001 1101 1110 1010
1010 1110 1111 1011
1011 1111 10000 00000 <-- zeroed, you know it ended
Because this was so fun, let's test your another example (mask = 49):
Here all values are in binary:
val = 00000, mask = 11001, ~mask = 00110 (bits inverted)
(old) (new)
val |~mask +1 &mask
00000 00110 00111 00001
00001 00111 01000 01000
01000 01110 01111 01001
01001 01111 10000 10000
10000 10110 10111 10001
10001 10111 11000 11000
11000 11110 11111 11001
11001 11111 100000 000000 <-- again, wrapped around (zeroed)
It's late and I did not actually tested on the computer. But this should work, or give the idea...

Bit shifting x * a number

How do you get number like -10 from these bit shifting practice problems?
From what I understand X*32 can be written as x<<5. But how are you to get numbers like x*66, or X*(-10)?
General Explanation
Bit shifting is primarily aimed to shift the binary representation of a number. It is not for multiplication.
23 = 0001 0111
23 << 1 = 0001 0111 << 1 = 0010 1110 = 46
However, as the binary representation of a number is changed, the
number it represents is also changed. This is just how computer binary system works. And thus people sometimes exploit this behavior as a "hack", mostly to speed up the computation time.
Let's try to understand it more:
Left bit-shift and right bit-shift
Now, when the number represented is of integer type, then shifting the binary representation of a number by 1 to the left will be equivalent to multiplying it by 2:
23 = 0001 0111
23 << 1 = 0001 0111 << 1 = 0010 1110 = 46 //left bit-shift by 1, number becomes doubled
Given that there is no overflow for the given data type:
255 = 1111 1111 //assuming 8-bit data type
255 << 1 = 1111 1111 << 1 = 1111 1110 = 254 //not multiplied by 2, because of overflow
While shifting integer number to the right will be equivalent as dividing it by 2 and then rounding it down:
23 = 0001 0111
23 >> 1 = 0001 0111 >> 1 = 000 1011 = 11 //right bit-shift by 1, number becomes halved, rounded down
Some use and link to multiplication and division
Since bit-shifting operation is typically less costly than multiplication, to speed things up, you will see in some program, people use left bit-shift operation (as a replacement of multiplication) when they mean to multiply it by an integer number of power of 2 (that is 2, 4, 8, 16, etc):
int a = 23;
...
a = a << 2; //=102; multiply by 4, equivalent to a = a * 4, but faster operation
Or use right bit-shift operation (as a replacement of division and rounding down) to divide it with an integer number of power of 2 (that is 2, 4, 8, 16, etc)
int a = 23;
...
a = a >> 2; //=5; divide by 4 and rounding down, equivalent to integer division a = a / 4, but faster
Concluding remarks
Note that only if you operate with number with power of 2, all the multiplications and divisions above can be replaced by left bit-shift or right bit-shift.
In your example, 66 and -10 are not integer number which of power of 2, thus you cannot "hack" the multiplication/division with binary-shifting operation.
In general, use bit-shift operation if you mean for bit-shifting, as bit-shifting has many other uses than just "hacking" for multiplication/division with integer number of power of 2. If you want to multiply or divide, be happy with just using multiplication (*) or division (/) operator.
Some additional remarks:
That being said, I would just like to add some more things regarding the bit-shift for further explanation (it won't do harm):
signed integer type can hold positive or negative number
there is a difference between logical bit-shift and arithmetic bit-shift when dealing with negative number. One will give 0 in the emptied-space after shift while the other will give 1
Hence, it probably best to note that the bit-shift is mainly used for unsigned type, such like for creating bit-masks by bit shifting. That is, unsigned is recommended to be used to avoid sign-extension surprises when you deal with negative number (right) bit-shift.

What does this ">>=" operator mean in 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

Resources