Bit shifting x * a number - c

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.

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.

Why does the following bitwise operation return an unintended result?

3 bits can hold up to a maximum number of 7 (4 + 2 + 1). I'm trying to calculate this using a bitwise operation.
3 is 0b011
~3 is 0b100
Doing a bitwise OR I would expect 0b111 (i.e. 7). Instead I get
int result = (~3) | 3;
printf("%i\n", result);
-1
What am I doing wrong?
You are doing everything right: N | ~N results in a number with binary representation consisting of all ones. Such number is interpreted as -1 in two's compliment representation of negative numbers.
How many bits wide is an int? You seem to think it's three bits wide. Certainly not correct! Guess again. What is ~0u? Try printf("%u\n", ~0u);. What about ~1u? ... and ~2u? Do you notice a pattern?
Note the u suffix, which tells the compiler that it's an unsigned literal. You can't work with signed integer types with the ~ operator... Well, you can, but you might run into trap representations and negative zeros, according to 6.2.6.2 of n1570.pdf. Using a trap representation is undefined behaviour. That might work on your system, but only by coincidence. Do you want to rely upon coincidence?
Similarly, I suggest using the %u directive to print unsigned values, as %d would produce undefined behaviour according to 7.21.6.1p29 of n1570.pdf.
When you do ~3 you are inverting the bits that make up 3 - so you turn 0000 0000 0000 0000 0000 0000 0000 0011 into 1111 1111 1111 1111 1111 1111 1111 1100. Since the high bit is set, this is interpreted as a negative number - all 1s is -1, one less than that is -2, one less -3 and so on. This number is the signed 32 bit integer for -4.
If you binary OR this with 3, you get all 1s (by definition) - which is the signed 32 bit integer for -1.
Your only problem is that you think you are working with 3 bit numbers, but you are actually working with 32 bit numbers.
After doing this in the code
int result = (~3) | 3;
Add this line
result= result & 0x07
This will give you the answer that you expect.
#include <stdio.h>
int main (){
unsigned d3 = 0b011;
unsigned invd3 = ~d3;
unsigned d4 = 0b100;
unsigned result = d3 | invd3;
printf("%X\n", result);//FFFFFFFF
result = d3 | d4;
printf("%X\n", result);//7
return 0;
}

What does >> and 0xfffffff8 mean?

I was told that (i >> 3) is faster than (i/8) but I can't find any information on what >> is. Can anyone point me to a link that explains it?
The same person told me "int k = i/8, followed by k*8 is better accomplished by (i&0xfffffff8);" but again Google didn't help m...
Thanks for any links!
As explained here the >> operator is simply a bitwise shift of the bits of i. So shifting i 1 bit to the right results in an integer-division by 2 and shifting by 3 bits results in a division by 2^3=8.
But nowadays this optimization for division by a power of two should not really be done anymore, as compilers should be smart enough to do this themselves.
Similarly a bitwise AND with 0xFFFFFFF8 (1...1000, last 3 bits 0) is equal to rounding down i to the nearest multiple of 8 (like (i/8)*8 does), as it will zero the last 3 bits of i.
Bitwise shift right.
i >> 3 moves the i integer 3 places to the right [binary-way] - aka, divide by 2^3.
int x = i / 8 * 8:
1) i / 8, can be replaced with i >> 3 - bitwise shift to the right on to 3 digits (8 = 2^3)
2) i & xfffffff8 comparison with mask
For example you have:
i = 11111111
k (i/8) would be: 00011111
x (k * 8) would be: 11111000
Therefore the operation just resets last 3 bits:
And comparable time cost multiplication and division operation can be rewritten simple with
i & xfffffff8 - comparison with (... 11111000 mask)
They are Bitwise Operations
The >> operator is the bit shift operator. It takes the bit represented by the value and shifts them over a set number of slots to the right.
Regarding the first half:
>> is a bit-wise shift to the right.
So shifting a numeric value 3 bits to the right is the same as dividing by 8 and inting the result.
Here's a good reference for operators and their precedence: http://web.cs.mun.ca/~michael/c/op.html
The second part of your question involves the & operator, which is a bit-wise AND. The example is ANDing i and a number that leaves all bits set except for the 3 least significant ones. That is essentially the same thing happening when you have a number, divide it by 8, store the result as an integer, then multiply that result by 8.
The reason this is so is that dividing by 8 and storing as an integer is the same as bit-shifting to the right 3 places, and multiplying by 8 and storing the result in an int is the same as bit-shifting to the left 3 places.
So, if you're multiplying or dividing by a power of 2, such as 8, and you're going to accept the truncating of bits that happens when you store that result in an int, bit-shifting is faster, operationally. This is because the processor can skip the multiply/divide algorithm and just go straight to shifting bits, which involves few steps.
Bitwise shifting.
Suppose I have an 8 -bit integer, in binary
01000000
If I left shift (>> operator) 1 the result is
00100000
If I then right shift (<< operator) 1, I clearly get back to wear I started
01000000
It turns out that because the first binary integer is equivelant to
0*2^7 + 1*2^6 + 0*2^5 + 0*2^4 + 0*2^3 + 1*2^2 + 0*2^1 + 0*2^0
or simply 2^6 or 64
When we right shift 1 we get the following
0*2^7 + 0*2^6 + 1*2^5 + 0*2^4 + 0*2^3 + 1*2^2 + 0*2^1 + 0*2^0
or simply 2^5 or 32
Which means
i >> 1
is the same as
i / 2
If we shift once more (i >> 2), we effectively divide by 2 once again and get
i / 2 / 2
Which is really
i / 4
Not quite a mathematical proof, but you can see the following holds true
i >> n == i / (2^n)
That's called bit shifting, it's an operation on bits, for example, if you have a number on a binary base, let's say 8, it will be 1000, so
x = 1000;
y = x >> 1; //y = 100 = 4
z = x >> 3; //z = 1
Your shifting the bits in binary so for example:
1000 == 8
0100 == 4 (>> 1)
0010 == 2 (>> 2)
0001 == 1 (>> 3)
Being as you're using a base two system, you can take advantage with certain divisors (integers only!) and just bit-shift. On top of that, I believe most compilers know this and will do this for you.
As for the second part:
(i&0xfffffff8);
Say i = 16
0x00000010 & 0xfffffff8 == 16
(16 / 8) * 8 == 16
Again taking advantage of logical operators on binary. Investigate how logical operators work on binary a bit more for really clear understanding of what is going on at the bit level (and how to read hex).
>> is right shift operation.
If you have a number 8, which is represented in binary as 00001000, shifting bits to the right by 3 positions will give you 00000001, which is decimal 1. This is equivalent to dividing by 2 three times.
Division and multiplication by the same number means that you set some bits at the right to zero. The same can be done if you apply a mask. Say, 0xF8 is 11111000 bitwise and if you AND it to a number, it will set its last three bits to zero, and other bits will be left as they are. E.g., 10 & 0xF8 would be 00001010 & 11111000, which equals 00001000, or 8 in decimal.
Of course if you use 32-bit variables, you should have a mask fitting this size, so it will have all the bits set to 1, except for the three bits at the right, giving you your number - 0xFFffFFf8.
>> shifts the number to the right. Consider a binary number 0001000 which represents 8 in the decimal notation. Shifting it 3 bits to the right would give 0000001 which is the number 1 in decimal notation. Thus you see that every 1 bit shift to the right is in fact a division by 2. Note here that the operator truncates the float part of the result.
Therefore i >> n implies i/2^n.
This might be fast depending on the implementation of the compiler. But it generally takes place right in the registers and therefore is very fast as compared to traditional divide and multiply.
The answer to the second part is contained in the first one itself. Since division also truncates all the float part of the result, the division by 8 will in theory shift your number 3 bits to the right, thereby losing all the information about the rightmost 3 bits. Now when you again multiply it by 8 (which in theory means shifting left by 3 bits), you are padding the righmost 3 bits by zero after shifting the result left by 3 bits. Therefore, the complete operation can be considered as one "&" operation with 0xfffffff8 which means that the number has all bits 1 except the rightmost 4 bits which are 1000.

Need help understanding "getbits()" method in Chapter 2 of K&R C

In chapter 2, the section on bitwise operators (section 2.9), I'm having trouble understanding how one of the sample methods works.
Here's the method provided:
unsigned int getbits(unsigned int x, int p, int n) {
return (x >> (p + 1 - n)) & ~(~0 << n);
}
The idea is that, for the given number x, it will return the n bits starting at position p, counting from the right (with the farthest right bit being position 0). Given the following main() method:
int main(void) {
int x = 0xF994, p = 4, n = 3;
int z = getbits(x, p, n);
printf("getbits(%u (%x), %d, %d) = %u (%X)\n", x, x, p, n, z, z);
return 0;
}
The output is:
getbits(63892 (f994), 4, 3) = 5 (5)
I get portions of this, but am having trouble with the "big picture," mostly because of the bits (no pun intended) that I don't understand.
The part I'm specifically having issues with is the complements piece: ~(~0 << n). I think I get the first part, dealing with x; it's this part (and then the mask) that I'm struggling with -- and how it all comes together to actually retrieve those bits. (Which I've verified it is doing, both with code and checking my results using calc.exe -- thank God it has a binary view!)
Any help?
Let's use 16 bits for our example. In that case, ~0 is equal to
1111111111111111
When we left-shift this n bits (3 in your case), we get:
1111111111111000
because the 1s at the left are discarded and 0s are fed in at the right. Then re-complementing it gives:
0000000000000111
so it's just a clever way to get n 1-bits in the least significant part of the number.
The "x bit" you describe has shifted the given number (f994 = 1111 1001 1001 0100) right far enough so that the least significant 3 bits are the ones you want. In this example, the input bits you're requesting are there, all other input bits are marked . since they're not important to the final result:
ff94 ...........101.. # original number
>> p+1-n [2] .............101 # shift desired bits to right
& ~(~0 << n) [7] 0000000000000101 # clear all the other (left) bits
As you can see, you now have the relevant bits, in the rightmost bit positions.
I would say the best thing to do is to do a problem out by hand, that way you'll understand how it works.
Here is what I did using an 8-bit unsigned int.
Our number is 75 we want the 4 bits starting from position 6.
the call for the function would be getbits(75,6,4);
75 in binary is 0100 1011
So we create a mask that is 4 bits long starting with the lowest order bit this is done as such.
~0 = 1111 1111
<<4 = 1111 0000
~ = 0000 1111
Okay we got our mask.
Now, we push the bits we want out of the number into the lowest order bits so
we shift binary 75 by 6+1-4=3.
0100 1011 >>3 0000 1001
Now we have a mask of the correct number of bits in the low order and the bits we want out of the original number in the low order.
so we & them
0000 1001
& 0000 1111
============
0000 1001
so the answer is decimal 9.
Note: the higher order nibble just happens to be all zeros, making the masking redundant in this case but it could have been anything depending on the value of the number we started with.
~(~0 << n) creates a mask that will have the n right-most bits turned on.
0
0000000000000000
~0
1111111111111111
~0 << 4
1111111111110000
~(~0 << 4)
0000000000001111
ANDing the result with something else will return what's in those n bits.
Edit: I wanted to point out this programmer's calculator I've been using forever: AnalogX PCalc.
Nobody mentioned it yet, but in ANSI C ~0 << n causes undefined behaviour.
This is because ~0 is a negative number and left-shifting negative numbers is undefined.
Reference: C11 6.5.7/4 (earlier versions had similar text)
The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed
type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
In K&R C this code would have relied on the particular class of system that K&R developed on, naively shifting 1 bits off the left when performing left-shift of a signed number (and this code also relies on 2's complement representation), but some other systems don't share those properties so the C standardization process did not define this behaviour.
So this example is really only interesting as a historical curiosity, it should not be used in any real code since 1989 (if not earlier).
Using the example:
int x = 0xF994, p = 4, n = 3;
int z = getbits(x, p, n);
and focusing on this set of operations
~(~0 << n)
for any bit set (10010011 etc) you want to generate a "mask" that pulls only the bits you want to see. So 10010011 or 0x03, I'm interested in xxxxx011. What is the mask that will extract that set ? 00000111 Now I want to be sizeof int independent, I'll let the machine do the work i.e. start with 0 for a byte machine it's 0x00 for a word machine it's 0x0000 etc. 64 bit machine would represent by 64 bits or 0x0000000000000000
Now apply "not" (~0) and get 11111111
shift right (<<) by n and get 11111000
and "not" that and get 00000111
so 10010011 & 00000111 = 00000011
You remember how boolean operations work ?
In ANSI C ~0 >> n causes undefined behavior
// the post about left shifting causing a problem is wrong.
unsigned char m,l;
m = ~0 >> 4; is producing 255 and its equal to ~0 but,
m = ~0;
l = m >> 4; is producing correct value 15 same as:
m = 255 >> 4;
there is no problem with left shifting negative ~0 << whatsoever

Resources