Summary
Bitwise operations are one of the basic operations in C/C ++. Even so, it is a strange operation for most programmersmost programmers seldom use bitwise operations. This article first briefly introduces the basic bitwise operators and their usage (when to use them), and then introduces several typical applications of bitwise operators:
(1) three instances that exchange two integers without temporary variables, and analyze the advantages and disadvantages of each instance
(2) In hexadecimal conversion, the decimal number is output in binary and hexadecimal notation through bitwise operations, and a general program is obtained for outputting the decimal number in hexadecimal notation of 2.
(3) The bitwise operation is used to calculate the number of 1 instances in the binary representation of an integer.
Unveil bit operations
All data is stored in binary format at the bottom of the computer. A data can be seen as an ordered bit set. Each digit has only two States: 0 or 1. Bitwise operations allow programmers to operate on a specific location of data, such as setting a value to 1 (or 0) and querying a certain State (1, or 0 ). Bitwise operations are composed of bitwise operators and operands. Different bitwise operators define different bitwise operations, the following table describes each bitwise operator and its corresponding bitwise operations and functions:
Bitwise operators
Bitwise operations
Usage
Function Description
~
Nonbitwise
~ Expr
Flip each bit of expr: 1 to 0, 0 to 1
<
Move left
Expr <n
Moving the expr to the left is discarded, and the right side is filled with 0. Therefore, the left side is multiplied by 2n.
>
Right Shift
Expr> n
Remove n digits from the expr to the right. If expr is of the unsigned type, add 0 to the left. Otherwise, insert a copy of the symbol bit on the left or 0 (depending on the specific implementation ).
&
Bitwise AND
Expr1 & expr2
If both expr1 and expr2 contain 1, the result is 1; otherwise, the result is 0.

By bit or
Expr1  expr2
Where each bit is located, if both expr1 and expr2 contain 0, the result is 0; otherwise, the result is 1.
^
Bitwise OR
Expr1 ^ expr2
If expr1 and expr2 are different in the location of each bit, the result is 1; otherwise, the result is 0.
In addition to the basic bitwise operators above, there are also composite symbols such as & =, ^ =, =, <<=, >>=, which are bitwise AND assign values respectively, bitwise OR assignment, bitwise OR assignment, left shift assignment, and right shift assignment. Next we will introduce how to implement bit operations:
1. Set the Nth (n starting from 0) bit of expr to 1: expr  = (1 <n );
2. Set the Nth (n starts from 0) bit of expr to 0: expr & = (~ (1 <n ));
3. Determine whether the Nth (n starting from 0) bit of expr is 1: bool B = expr & (1 <n );
4. Flip the nth digit (n starts from 0) of the expr: expr ^ = (1 <n );
Note:
1. The C standard provides bitset for a variety of bit operations. You can enter bitset in MSDN to learn the relevant content. The header file must be included: # include "bitset ".
2. bitwise operations can only be used to operate on numbers of integer types, such as char, short, int, and long (including signed and unsigned). Do not operate on floating point numbers, such as float and double! Std: the parameter of the bitset constructor is unsigned long int. Try not to operate on negative numbers because of poor portability, different system platforms have different definitions for the rightshift operation of negative numbers (most platforms require highend signup bits, and some platforms require highend 0 ).
Bitwise operation Example 1: Exchange two integers without any intermediate Variables
This is a classic question. You can easily find multiple answers online. Here I will provide two solutions:
Solution 1: implement with arithmetic operations (an imperfect solution)
The solution has a simple idea and a short implementation code, as shown below:
Template <class T>
Void mySwap_1 (T & a, T & B)
{
A = a + B;
B = aB;
A = aB;
}
Simple, but I want to give it a simple explanation: the first sentence a = a + B is to use a to save the sum of the original a and original B; the second sentence B = aB; so that the original a value is saved to B; the last sentence a = aB; so that the original B value is saved to.
We can say that this method is not so perfect because the result overflow may occur in arithmetic operations. If a and B are very large, then the first sentence a = a + B will cause result overflow. For example, if the original a = 2147483647, B = 2, then a + B is 2147483649, this number is greater than the maximum unsigned integer 2147483648, so overflow occurs. The result saved in a is actually2147483647, but it is surprising that: although the result of the first program is2147483647, the result of the last two statements is correct, that is, the values of the original a and B can be exchanged, that is: only the results in the first sentence are incorrect, but the final results are correct. I am confused about this. I have not figured out the reason yet. I would like to ask you again!
Finally, let's talk about the advantages of this method over solution 2: This method can be used to exchange two nonINTEGER (floating point number), while solution 2 is based on bitwise operations, the bitwise operation cannot be directly used for floating point numbers. Therefore, solution 2 cannot be used to exchange two floating point numbers!
Solution 2: implement with bitwise operations (better solution)
The solution code is similar to solution 1, and the idea is not difficult. Let's look at the code first, and then let's look at my lengthy analysis:
Template <class T>
Void mySwap_2 (T & a, T & B)
{
A = a ^ B;
B = B ^;
A = a ^ B;
}
This exchange function is no stranger to programmers, but I believe that some of these programmers only remember to write the code and do not know why the three statements of code are written, as a matter of fact, at the beginning, I thought it would be better to simply remember the three lines of code that made me spend time understanding analysis. As a matter of fact, when I wrote this article today, I was willing to consume some brain cells to understand it. Next I tried to elaborate on the above three statements. For convenience, let's assume that the data type is char, and a = 5, B = 3; in the memory, a and B are stored as follows:
A:
0
0
0
0
0
1
0
1
B:
0
0
0
0
0
0
1
1
Next, we will analyze each sentence in detail:
First, let's look at the first sentence: a = a ^ B; after this statement is executed, the difference BITs between a and B are saved in a. That is to say, if a bit of a and B is different, then the location of a is 1, so a becomes like this in the memory. It indicates that the second and second bits of a and B are different:
A:
0
0
0
0
0
1
1
0
Next let's look at the second sentence: B = B ^ a; it means to flip the bits with different bits in B, so that the value saved in B is actually equal to the value in original, remember that after the second statement is executed, a still saves the difference information of the original a and B, and B changes to the original!
Finally, let's look at the third sentence: a = a ^ B; because the XOR operation satisfies the exchange law, this sentence is equivalent to: a = B ^; remember that the original a value has been saved in B on the right of the value assignment, while the original a and B differences are saved in, therefore, the final function of this sentence is to flip (change to B) the bitwise of the original a and assign it to a, so that the original B value is saved in.
Conclusion: In the above three sentences, the first sentence is to record the differences, and the second and second sentences are flipped. Finally, the values of the two variables are exchanged without any intermediate variables.
Analysis: bitwise operations do not consider the carry issue, so there is no result overflow problem! However, since it is not possible to perform direct bitwise operations on floating point numbers, this method cannot be used to exchange two floating point numbers! Of course, the original question is to exchange two integers.
Note: There are other methods to achieve two data exchanges, such as using memory copy! Because it does not belong to the bit operation category, we will not go into details here.
Bitwise Application Example 2: hexadecimal conversion
Requirements: the decimal integers are output in binary and hexadecimal notation respectively.
Two methods are provided to achieve binary output:
Method 1: Since integers are stored in binary format in a computer, we only need to print each bit in order. If a bit is 1, the character '1' is printed ', otherwise, the character '0' is printed '. The code I provided is as follows:
VoidprintBinary (int num)
{
For (int I = 0; I <32; I ++)
{
Cout <(num> (31i) & 1 );
// Cout <(num & (1 <(31i) = 0? 0: 1 );
}
}
The commentedout cout has the same function as the uncommented cout! The idea of this function is very simple, that is, to print every bit from the height to the bottom. The code above is a bit bad, that is, the statement is too complicated. A cout statement does too many things. If it affects your understanding, you can add several temporary variables, split the statement into multiple simple statements. I write this mainly for space reasons, so the program section is too spaceconsuming. When programming, the statement strives to be simple and clear: One Line writes only one statement, and one statement does only one thing!
Method 2: Implement bitset
Bitset is a class (not a container) provided by the standard library. It can be used to conveniently operate bits. The following is a program implemented using bitset:
VoidprintBinary (int num)
{
Bitset <32> bits = bitset <32> (unsigned long) (num ));
For (int I = 31; I> = 0; I )
{
Cout <(bits [I] = true? '1': '0 ');
}
}
Note: bitset overload multiple operators, including the subscript operator []. You can conveniently obtain a bit and check whether it is 1. For more information about bitset, refer to msdn or other materials. You only need to remember that bitset is provided by the standard library and can be used at any time. Do not forget to add the corresponding header file.
Implement hexadecimal output:
Similarly, because the data is stored in the memory in binary format, we can output integers in hexadecimal notation as follows: from left to right, a group of 4 bits each, combine them into a hexadecimal number and output them at a time. The program is as follows:
Void printHex (int num)
{
For (inti = 28; I> = 0; I= 4)
{
Int temp = num> I;
Temp = temp & 15; // 15 is the mask!
Char ch;
Temp> 9? (Ch = 'A' + temp10) :( ch = '0' + temp );
Cout <ch;
}
}
This program is very similar to the printBinary function above. Note that I changes 4 every time. The most important thing is that the statement temp = temp & 15; because it is in hexadecimal format, so here we use 15 as the mask. I want to pave the way for printBinary. It is not difficult to understand this printHex. I will not repeat it here. Next, I will make a small extension to these two functions: Implement integerbased output in 2n (n of 2! For example, it can be in octal or 32 hexadecimal format. For ease of description, we limit 1 <= n <= 6; and use the characters '0' to '9' to indicate numbers 0 to 9. Use the characters A, B ,...... Z, a, B ,...... The value ranges from 10 to 63. The procedure is as follows:
Void print2powerN (int num, int N)
{
For (inti = 32N; I> = 0; I= N)
{
Int temp = num> I;
Temp = temp & (1 <N)1 );
Char ch;
If (temp <= 9)
{
Ch = '0' + temp;
}
Elseif (temp <= 35)
{
Ch = 'A' + temp10;
}
Else
{
Ch = 'A' + temp36;
}
Cout <ch;
}
}
Note: bitwise operations can also achieve conversion in decimal to any expected hexadecimal format. This problem is quite difficult and I have not yet completed it!
Bitwise Case 3: Evaluate the number of 1 in the binary representation of an integer
Problem description: input an integer N and output its binary representation of the number M of 1. For example, if N = 13, M = 3;
Analysis: there are more than one solution to this problem, which can be implemented by scanning each bit in binary representation. The complexity of this solution is o (n) n is the total number of digits in the binary representation of N. This section describes how to use bitwise operations to solve the problem and ensure that the complexity is lower than o (n). In fact, the complexity of this method is o (m ), where m is the number of 1 in the binary ID of N!
Idea: Let's take a look at the specific implementation: n & (n1) can flip the 1 of the second bit! For example, if n = 108 and its binary value is 01101100, the result of n & (n1) is 01101000. Therefore, as long as you constantly flip the 1 of the second bit of n, each time you flip the counter, let the counter + 1 until n is equal to 0, the counter records the 1digit number of the second of n, the procedure is as follows:
Int count1Bits (long n)
{
Int count = 0;
While (n)
{
Count ++;
N & = (n1 );
}
Return count;
}
Note: For other methods to solve this problem, see the beauty of programming. Another use of n & (n1) is to determine whether n is an integer power of 2.
At this point, this article is over. I found that every time I write something recently, I can use a proverb to describe it: lazy motherinlaw's feetsmelly and long! No way. Every time I think about writing something, my thinking is very divergent (maybe it is more appropriate to describe it in disorder). It seems that I have to summarize the major topics in the future. In addition, due to the recent hot weather, impetuous mood, and dizzy mind, the code in this article has poor considerations, please criticize and correct me.