I'm someone who writes code just for fun and haven't really delved into it in either an academic or professional setting, so stuff like these bitwise operators really escapes me.
I was reading an article about JavaScript, which apparently supports bitwise operations. I keep seeing this operation mentioned in places, and I've tried reading about to figure out what exactly it is, but I just don't seem to get it at all. So what are they? Clear examples would be great! :D
Just a few more questions - what are some practical applications of bitwise operations? When might you use them?
Since nobody has broached the subject of why these are useful:
I use bitwise operations a lot when working with flags. For example, if you want to pass a series of flags to an operation (say, File.Open(), with Read mode and Write mode both enabled), you could pass them as a single value. This is accomplished by assigning each possible flag it's own bit in a bitset (byte, short, int, or long). For example:
Read: 00000001
Write: 00000010
So if you want to pass read AND write, you would pass (READ | WRITE) which then combines the two into
00000011
Which then can be decrypted on the other end like:
if ((flag & Read) != 0) { //...
which checks
00000011 &
00000001
which returns
00000001
which is not 0, so the flag does specify READ.
You can use XOR to toggle various bits. I've used this when using a flag to specify directional inputs (Up, Down, Left, Right). For example, if a sprite is moving horizontally, and I want it to turn around:
Up: 00000001
Down: 00000010
Left: 00000100
Right: 00001000
Current: 00000100
I simply XOR the current value with (LEFT | RIGHT) which will turn LEFT off and RIGHT on, in this case.
Bit Shifting is useful in several cases.
x << y
is the same as
x * 2y
if you need to quickly multiply by a power of two, but watch out for shifting a 1-bit into the top bit - this makes the number negative unless it's unsigned. It's also useful when dealing with different sizes of data. For example, reading an integer from four bytes:
int val = (A << 24) | (B << 16) | (C << 8) | D;
Assuming that A is the most-significant byte and D the least. It would end up as:
A = 01000000
B = 00000101
C = 00101011
D = 11100011
val = 01000000 00000101 00101011 11100011
Colors are often stored this way (with the most significant byte either ignored or used as Alpha):
A = 255 = 11111111
R = 21 = 00010101
G = 255 = 11111111
B = 0 = 00000000
Color = 11111111 00010101 11111111 00000000
To find the values again, just shift the bits to the right until it's at the bottom, then mask off the remaining higher-order bits:
Int Alpha = Color >> 24
Int Red = Color >> 16 & 0xFF
Int Green = Color >> 8 & 0xFF
Int Blue = Color & 0xFF
0xFF is the same as 11111111. So essentially, for Red, you would be doing this:
Color >> 16 = (filled in 00000000 00000000)11111111 00010101 (removed 11111111 00000000)
00000000 00000000 11111111 00010101 &
00000000 00000000 00000000 11111111 =
00000000 00000000 00000000 00010101 (The original value)
It is worth noting that the single-bit truth tables listed as other answers work on only one or two input bits at a time. What happens when you use integers, such as:
int x = 5 & 6;
The answer lies in the binary expansion of each input:
5 = 0 0 0 0 0 1 0 1
& 6 = 0 0 0 0 0 1 1 0
---------------------
0 0 0 0 0 1 0 0
Each pair of bits in each column is run through the "AND" function to give the corresponding output bit on the bottom line. So the answer to the above expression is 4. The CPU has done (in this example) 8 separate "AND" operations in parallel, one for each column.
I mention this because I still remember having this "AHA!" moment when I learned about this many years ago.
Bitwise operators are operators that work on a bit at a time.
AND is 1 only if both of its inputs are 1.
OR is 1 if one or more of its inputs are 1.
XOR is 1 only if exactly one of its inputs are 1.
NOT is 1 only if its input are 0.
These can be best described as truth tables. Inputs possibilities are on the top and left, the resultant bit is one of the four (two in the case of NOT since it only has one input) values shown at the intersection of the two inputs.
AND|0 1 OR|0 1
---+---- ---+----
0|0 0 0|0 1
1|0 1 1|1 1
XOR|0 1 NOT|0 1
---+---- ---+---
0|0 1 |1 0
1|1 0
One example is if you only want the lower 4 bits of an integer, you AND it with 15 (binary 1111) so:
203: 1100 1011
AND 15: 0000 1111
------------------
IS 11: 0000 1011
These are the bitwise operators, all supported in JavaScript:
op1 & op2 -- The AND operator compares two bits and generates a result of 1 if both bits are 1; otherwise, it returns 0.
op1 | op2 -- The OR operator compares two bits and generates a result of 1 if the bits are complementary; otherwise, it returns 0.
op1 ^ op2 -- The EXCLUSIVE-OR operator compares two bits and returns 1 if either of the bits are 1 and it gives 0 if both bits are 0 or 1.
~op1 -- The COMPLEMENT operator is used to invert all of the bits of the operand.
op1 << op2 -- The SHIFT LEFT operator moves the bits to the left, discards the far left bit, and assigns the rightmost bit a value of 0. Each move to the left effectively multiplies op1 by 2.
op1 >> op2 -- The SHIFT RIGHT operator moves the bits to the right, discards the far right bit, and assigns the leftmost bit a value of 0. Each move to the right effectively divides op1 in half. The left-most sign bit is preserved.
op1 >>> op2 -- The SHIFT RIGHT - ZERO FILL operator moves the bits to the right, discards the far right bit, and assigns the leftmost bit a value of 0. Each move to the right effectively divides op1 in half. The left-most sign bit is discarded.
In digital computer programming, a bitwise operation operates on one or more bit patterns or binary numerals at the level of their individual bits. It is a fast, primitive action directly supported by the processor, and is used to manipulate values for comparisons and calculations.
operations:
bitwise AND
bitwise OR
bitwise NOT
bitwise XOR
etc
List item
AND|0 1 OR|0 1
---+---- ---+----
0|0 0 0|0 1
1|0 1 1|1 1
XOR|0 1 NOT|0 1
---+---- ---+---
0|0 1 |1 0
1|1 0
Eg.
203: 1100 1011
AND 15: 0000 1111
------------------
= 11: 0000 1011
Uses of bitwise operator
The left-shift and right-shift operators are equivalent to multiplication and division by x * 2y respectively.
Eg.
int main()
{
int x = 19;
printf ("x << 1 = %d\n" , x <<1);
printf ("x >> 1 = %d\n", x >>1);
return 0;
}
// Output: 38 9
The & operator can be used to quickly check if a number is odd or even
Eg.
int main()
{
int x = 19;
(x & 1)? printf("Odd"): printf("Even");
return 0;
}
// Output: Odd
Quick find minimum of x and y without if else statement
Eg.
int min(int x, int y)
{
return y ^ ((x ^ y) & - (x < y))
}
Decimal to binary
conversion
Eg.
#include <stdio.h>
int main ()
{
int n , c , k ;
printf("Enter an integer in decimal number system\n " ) ;
scanf( "%d" , & n );
printf("%d in binary number
system is: \n " , n ) ;
for ( c = 31; c >= 0 ; c -- )
{
k = n >> c ;
if ( k & 1 )
printf("1" ) ;
else
printf("0" ) ;
}
printf(" \n " );
return 0 ;
}
The XOR gate encryption is popular technique, because of its complixblity and reare use by the programmer.
bitwise XOR operator is the most useful operator from technical interview perspective.
bitwise shifting works only with +ve number
Also there is a wide range of use of bitwise logic
To break it down a bit more, it has a lot to do with the binary representation of the value in question.
For example (in decimal):
x = 8
y = 1
would come out to (in binary):
x = 1000
y = 0001
From there, you can do computational operations such as 'and' or 'or'; in this case:
x | y =
1000
0001 |
------
1001
or...9 in decimal
Hope this helps.
When the term "bitwise" is mentioned, it is sometimes clarifying that is is not a "logical" operator.
For example in JavaScript, bitwise operators treat their operands as a sequence of 32 bits (zeros and ones); meanwhile, logical operators are typically used with Boolean (logical) values but can work with non-Boolean types.
Take expr1 && expr2 for example.
Returns expr1 if it can be converted
to false; otherwise, returns expr2.
Thus, when used with Boolean values,
&& returns true if both operands are
true; otherwise, returns false.
a = "Cat" && "Dog" // t && t returns Dog
a = 2 && 4 // t && t returns 4
As others have noted, 2 & 4 is a bitwise AND, so it will return 0.
You can copy the following to test.html or something and test:
<html>
<body>
<script>
alert("\"Cat\" && \"Dog\" = " + ("Cat" && "Dog") + "\n"
+ "2 && 4 = " + (2 && 4) + "\n"
+ "2 & 4 = " + (2 & 4));
</script>
It might help to think of it this way. This is how AND (&) works:
It basically says are both of these numbers ones, so if you have two numbers 5 and 3 they will be converted into binary and the computer will think
5: 00000101
3: 00000011
are both one: 00000001
0 is false, 1 is true
So the AND of 5 and 3 is one. The OR (|) operator does the same thing except only one of the numbers must be one to output 1, not both.
I kept hearing about how slow JavaScript bitwise operators were. I did some tests for my latest blog post and found out they were 40% to 80% faster than the arithmetic alternative in several tests. Perhaps they used to be slow. In modern browsers, I love them.
I have one case in my code that will be faster and easier to read because of this. I'll keep my eyes open for more.
Related
I'm very new to C and i'm trying to understand bitwise operators in C
I found this code in front of me (to convert 2 to 37)
int main(void)
{
int x = 2;
x = (x<<x<<x) | (x<<x<<x) | (x << !!x) | !!x ;
printf("%d\n" , x ); // prints 37
}
Now it's the first time i see something like this (x<<x<<x) and i don't understand what it is doing.
Can anyone please explain the second line in code in detail?
I'd recommend you to split this long line into few small pieces (sometimes it is more effective to try such things; i.e. reading of the documentation only is not enough):
int x = 2;
printf("%d\n", x); // prints 2
printf("%d\n", x << x); // prints 8
printf("%d\n", x << x << x); // prints 32
printf("%d\n", !!x); // prints 1
printf("%d\n", x << !!x); // prints 4
printf("%d\n", x); // prints 2 (just to become sure that x was not changed)
So, you know that initial long line is equal to x = (32 | 32 | 1 | 4). But this is 32+4+1=37.
Let's see in details:
What is << and >>?
The shift operators bitwise shift the value on their left by the number of bits on their right:
<< shifts left and adds zeros at the right end.
>> shifts right and adds either 0s, if value is an unsigned type, or extends the top bit (to preserve the sign) if its a signed type.
Also the C standard says about E1 >> E2: "If E1 has a signed type and a negative value, the resulting value is implementation-defined." Arithmetic shift is not guaranteed.
Since << is left associative, x<<x<<x is evaluated as (x<<x)<<x.
See also: What are bitwise shift (bit-shift) operators and how do they work?
What is !!x?
It is an unary NOT and an unary NOT.
!!x can be used as shorthand for (x != 0 ? 1 : 0).
This is known as "obfuscation": writing needlessly complex code in order to make something seem more advanced that it is.
Looking at the sub-expression x<<x<<x, it is simple logical left shifts. The operator associativity of shift operators is left-to-right, so the expression is equal to (x<<x)<<x.
We left shift
2 by 2 and get 8. 8 << 2, left shift 8 by 2 and get 32:
x = 32 | 32 | (x << !!x) | !!x ;
Then for any expression with bitwise OR 32 | 32 where the operands 32 are identical, is the very same thing as just writing 32 without the OR. So it is equivalent to:
x = 32 | (x << !!x) | !!x ;
!! is a somewhat common though obscure trick in C to convert any integer to a boolean value 0 or 1. !! is not one operator, but two times the logical not operator !. First we have !2 which is 0. Then !0 which gives 1. We are left with this:
x = 32 | (2 << 1) | 1;
2 << 1 is 4, so:
x = 32 | 4 | 1;
Write it in binary:
0010 0000
OR 0000 0100
OR 0000 0001
------------
0010 0101 = 0x25 hex = 37 dec
I am trying to understand a CRC-32 algorithm. Is there an equivalent expression for:
y = (X >> 31) ^ (data >> 7);
using &, something like
y = (x & 0x8000) ^ (data & 0x800)
Well it depends on your calculations but in bit operations each operator has its own motive to do things. Same answer can be obtained by different operations but that doesn't mean that operator to equivalent to each other. Each operator has different motive to achieve.
bit a bit b a & b (a AND b) a | b (a OR b) a ^ b (a XOR b)
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0
The purpose of << and >> is to shit bits/drop bits from calculations
Right Shift
The symbol of right shift operator is >>. For its operation, it requires two operands. It shifts each bit in its left operand to the right. The number following the operator decides the number of places the bits are shifted (i.e. the right operand). Thus by doing ch >> 3 all the bits will be shifted to the right by three places and so on.
i = 14; // Bit pattern 1110
j = i >> 1; // bit pattern shifted 1 thus we get 111 = 7 = 14/2
Left shift
The symbol of left shift operator is <<. It shifts each bit in its left-hand operand to the left by the number of positions indicated by the right-hand operand. It works opposite to that of right shift operator. Thus by doing ch << 1 in the above example we have 11001010. Blank spaces generated are filled up by zeroes as above.
Left shift can be used to multiply an integer in multiples of 2 as in:
int i = 4; /* bit pattern equivalent is 100 */
int j = i << 2; /* makes it 10000, original number by 4 i.e. 16 */
Please help out with understanding of the output of the following c program statement.
a = ~a + 2 << 1 ;
printf("Value of A is %d",a);
Value of A comes out to be -2.
I am assuming that a is an signed int and initialized as 2. I am also assuming this is two's complement. (I have also omitted the bytes above the first byte as they don't have a meaning on the result of this answer).
The ~ (tilde) is the bitwise not operator. That is it will make any 1 into 0 and any 0 into 1. The << is a bit shift to the left operation.
So in the start we got 00000010 as the bits in a. As we do the not operator we get 11111101 which would give us the number -3.
We then add 2 to that so we get 11111111 or -1. We then bitshift this one to the left and we have 11111110 which equals -2.
I'm trying to learn C on my own. I came across this exercise and i am studying to understand it. I have read about masking bits and in order to get the last four bits we should do val&0xF.I have read this post as well What is Bit Masking?. The part that i need an explanation is why the possible values are 0x7,0xB,0xD,0xE,0xF. I am studying the answer and i have read various articles. If someone is willing to explain to me this part i would appreciate it.
Because these are all the possible numbers with at least three of the last four bits on. If you write down every binary number from 0 to 15, you will see that these have at least three of the last four bits set:
0111 (0x7)
1011 (0xB)
1101 (0xD)
1110 (0xE)
1111 (0xF)
Think of it like this: every binary number from 0 to 6 has at most 2 bits set:
0 (0)
1 (1)
10 (2)
11 (3)
100 (4)
101 (5)
110 (6)
Thus, none of it matches the rule. From 7 up to 15, we have:
111 (7)
1000 (8)
1001 (9)
1010 (10)
1011 (11)
1100 (12)
1101 (13)
1110 (14)
1111 (15)
From these, only 7, 11, 13, 14 and 15 have three of the last four bits set.
This method is easy to implement:
int chk_last_bits2(unsigned x) {
return ((x & 0x7) == 0x7) ||
((x & 0xB) == 0xB) ||
((x & 0xD) == 0xD) ||
((x & 0xE) == 0xE) ||
((x & 0xF) == 0xF);
}
Note that we have to explicitly test for equality for each case. For example, x & 0xB will return a non-zero value for every number with any of 1011 bits set. This is not what we want, we want all of them to be on, which can be tested with equality.
Another possible solution would be:
int chk_last_bits(unsigned x) {
int i, j;
for (i = 1, j = 0; i < 32; i <<= 1)
if (i & x)
j++;
return j >= 3;
}
Since you're learning C, I'll leave this one for you to try to understand.
Masking means filtering bits and keeping only some of them, which are of interest, as you will have understood.
Let's say that you have a variable something and a mask, both are unsigned values: something & mask will return a value whose bits are 0 where the mask is 0 and the value they had in something where the mask is 1. This is the and mask.
To understand why you use those particular values, you have to recall how bitwise operations (&, |...) work in C. When you write a & b, then the corresponding bits of the two variables are orderly combined using the specified logical operator. For instance, if a is 10001010 and b is 00000011, then a & b is 00000010 (orderly, 1 and 0, 0 and 0, 0 and 0, 0 and 0, 1 and 0, 0 and 0, 1 and 1, 0 and 1).
If you understood that, then you can understand what those masks will select. Consider their binary representation:
0x7 --> ...00000111 --> the three LSBs
0xb --> ...00001011 --> the first, second and fourth LSBs
0xd --> ...00001101 --> the first, third and fourth LSBs
0xe --> ...00001110 --> the second, third and fourth LSBs
0xf --> ...00001111 --> the 4 LSBs
This was for and masking, which is for extracting values (refer to the answer you linked). xor and or masking would work similarly, just recall how the logical function behaves.
#include <stdio.h>
int main()
{
/*
32 Bit binary: 00000000000000001100101011111110
Decimal: 51966
*/
int val = 0xCAFE;
/*
Note:
First it does loop, after that it shifts the bits of `i`,
so `i` is 1 at the beginning.
When shifting operator appears always think of bits.
Step 1
Decimal: i = 1
32 Bit binary: 00000000000000000000000000000001
Step 2
Decimal: 1 << 1 = 2
32 Bit binary: 00000000000000000000000000000010
Step 3
Decimal: 2 << 1 = 4
32 Bit binary: 00000000000000000000000000000100
... and so on ... 1, 2, 4, 8, 16, 32, stop.
This indicates 2^n.
----------------------------------------------------------------
Inside the for loop we run the AND operator to find out
which bits are `on` and which are `off`.
AND only works if both are true.
Step 1:
Last bit
00000000000000000000000000000001
AND 00000000000000001100101011111110
---------------------------------
00000000000000000000000000000000
Decimal: 1
Second last bit
Step 2:
00000000000000000000000000000010
AND 00000000000000001100101011111110
---------------------------------
00000000000000000000000000000010
Decimal: 2
... and so on ...
As we can see we gradually check for last 4 bits until
we reach the 4th loop 2^4 = 32 and the loop stops.
*/
int i;
for (i = 1; i < 32; i = i << 1) {
/*
You can simply add a counter over here
and return the value at the end.
*/
printf("%d\n", i & val);
}
}
I'm looking at a datasheet specification of a NIC and it says:
bits 2:3 of register contain the NIC speed, 4 contains link state, etc. How can I isolate these bits using bitwise?
For example, I've seen the code to isolate the link state which is something like:
(link_reg & (1 << 4))>>4
But I don't quite get why the right shift. I must say, I'm still not fairly comfortable with the bitwise ops, even though I understand how to convert to binary and what each operation does, but it doesn't ring as practical.
It depends on what you want to do with that bit. The link state, call it L is in a variable/register somewhere
43210
xxxxLxxxx
To isolate that bit you want to and it with a 1, a bitwise operation:
xxLxxxx
& 0010000
=========
00L0000
1<<4 = 1 with 4 zeros or 0b10000, the number you want to and with.
status&(1<<4)
This will give a result of either zero or 0b10000. You can do a boolean comparison to determine if it is false (zero) or true (not zero)
if(status&(1<<4))
{
//bit was on/one
}
else
{
//bit was off/zero
}
If you want to have the result be a 1 or zero, you need to shift the result to the ones column
(0b00L0000 >> 4) = 0b0000L
If the result of the and was zero then shifting still gives zero, if the result was 0b10000 then the shift right of 4 gives a 0b00001
so
(status&(1<<4))>>4 gives either a 1 or 0;
(xxxxLxxxx & (00001<<4))>>4 =
(xxxxLxxxx & (10000))>>4 =
(0000L0000) >> 4 =
0000L
Another way to do this using fewer operations is
(status>>4)&1;
xxxxLxxxx >> 4 = xxxxxxL
xxxxxxL & 00001 = 00000L
Easiest to look at some binary numbers.
Here's a possible register value, with the bit index underneath:
00111010
76543210
So, bit 4 is 1. How do we get just that bit? We construct a mask containing only that bit (which we can do by shifting a 1 into the right place, i.e. 1<<4), and use &:
00111010
& 00010000
----------
00010000
But we want a 0 or a 1. So, one way is to shift the result down: 00010000 >> 4 == 1. Another alternative is !!val, which turns 0 into 0 and nonzero into 1 (note that this only works for single bits, not a two-bit value like the link speed).
Now, if you want bits 3:2, you can use a mask with both of those bits set. You can write 3 << 2 to get 00001100 (since 3 has two bits set). Then we & with it:
00111010
& 00001100
----------
00001000
and shift down by 2 to get 10, the desired two bits. So, the statement to get the two-bit link speed would be (link_reg & (3<<2))>>2.
If you want to treat bits 2 and 3 (starting the count at 0) as a number, you can do this:
unsigned int n = (link_get & 0xF) >> 2;
The bitwise and with 15 (which is 0b1111 in binary) sets all but the bottom four bits to zero, and the following right-shift by 2 gets you the number in bits 2 and 3.
you can use this to determine if the bit at position pos is set in val:
#define CHECK_BIT(val, pos) ((val) & (1U<<(pos)))
if (CHECK_BIT(reg, 4)) {
/* bit 4 is set */
}
the bitwise and operator (&) sets each bit in the result to 1 if both operands have the corresponding bit set to 1. otherwise, the result bit is 0.
The problem is that isolating bits is not enough: you need to shift them to get the correct size order of the value.
In your example you have bit 2 and 3 for the size (I'm assuming that least significant is bit 0), it means that it is a value in range [0,3]. Now you can mask these bits with reg & (0x03<<2) or, converted, (reg & 0x12) but this is not enough:
reg 0110 1010 &
0x12 0000 1100
---------------
0x08 0000 1000
As you can see the result is 1000b which is 8, which is over the range. To solve this you need to shift back the result so that the least significant bit of the value you are interested in corresponds to the least significant bit of the containing byte:
0000 1000 >> 2 = 10b = 3
which now is correct.