Bit operation and its application example (1)
Summary
Bit operations are one of the basic operations in C/s + +, and even so, it is a strange operation for most programmers-most programmers seldom use bit arithmetic. This article first briefly introduces the basic bitwise operator and its usage (when used), and then introduces several typical applications of the bitwise operators:
(1) Three instances of exchanging two integers without a temporary variable , and analyzing the pros and cons of each instance
(2) The binary conversion , through the bit operation to achieve the decimal number in binary and hexadecimal output, and a general, for the decimal in accordance with the n-th binary output of the program.
(3) gives the number of 1 instances in the binary representation of a computed integer that is implemented by a bitwise operation.
Uncover the veil of bit arithmetic
All data is stored in binary storage at the bottom of the computer, and a data can be viewed as an ordered set of bits. There are only two states for each of them: 0 or 1. Bit operations allow a programmer to manipulate a particular bit of data, such as setting a bit to 1 (or 0), and querying the state of a bit (1, or 0). Bitwise operations consist of bitwise operators and operands, and different bitwise operators define different bit operations, and the following table describes each bitwise operator and its corresponding bitwise operations and functions:
Bitwise operator |
The corresponding bit operation |
Usage |
Function description |
~ |
Bitwise non- |
~expr |
Flip each bit of expr: 1 to 0,0 1 |
<< |
Move left |
Expr<<n |
Move expr to the left N-bit, move to the outside of the discarded, to the right of the bit 0, so the left shift n is equal to multiplying by 2n |
>> |
Move right |
Expr>>n |
Move expr to the right N-bit, move it to the outside of the discarded, if expr is an unsigned type, the left side is 0, otherwise, the left side inserts a copy of the symbol bit or 0 (depending on the implementation). |
& |
Bitwise-AND |
Expr1&expr2 |
where each bit is located, if both Expr1 and EXPR2 contain 1, the result is 1, otherwise 0. |
| |
Bitwise OR |
EXPR1 | Expr2 |
where each bit is located, if both Expr1 and expr2 contain 0, the result is 0, otherwise 1. |
^ |
Bitwise XOR OR |
Expr1 ^ expr2 |
where each bit is located, if Expr1 and expr2 are not the same, the result is 1, otherwise 0. |
In addition to the basic bitwise operators above, there are &=,^=,|=,<<=,>>= and other combinations of symbols, which are: bitwise AND assignment, bitwise XOR or assignment, bitwise OR assignment, left shift assignment, right shift assignment. Next you'll learn how to implement bit operations:
1. Set the nth (n starting 0) bit of expr to 1:expr |= (1<<n);
2. Set the nth (n from 0) bit of expr to 0:expr &= (~ (1<<n));
3. Determine if the nth (n starting from 0) bit of expr is 1:bool B =expr & (1<<n);
4. Flip the nth (n from 0) bit of expr: expr ^= (1<<n);
Attention
1. The C standard provides bitset for various bit operations, you can enter Bitset in MSDN to learn about the content, you need to include the header file: #include "Bitset".
2. Bitwise operations can only be used for operations with numbers of integer types, such as Char,short,int,long (including signed and unsigned), cannot operate floating-point numbers, such as float,double! Std::bitset constructor parameters are unsigned long int, try not to operate on negative numbers, because the portability is poor, different system platform for negative right shift operation definition is not the same (most of the platform specifies the high-fill sign bit, some platform provides high-level complement 0).
Bit Operations Application Example 1: Swap two integers without any intermediate variables
This question is more classic, you can easily find a variety of answers online, I am here to give two scenarios:
Scenario 1: Implementation with arithmetic operations (an imperfect scheme)
The idea of the scheme is simple, the implementation code is very short, as follows:
[CPP]View Plaincopyprint?
- template<class t>
- Void Myswap_1 (t& A, t& b)
- {
- A = A+b;
- b = a A;
- A = a-B;
- }
Template<class t>void myswap_1 (t& A, t& b) { a = a+b; b = a A; A = a-B;}
Simple, but I would like to say briefly: the first sentence a=a+b, is to use a to save the original A and the original B and the second sentence B = A-B, so that the value of the original A is saved to the inside, the last sentence a=a-b, so that the value of the original B is saved to a inside.
We say that this method is not so perfect, because the arithmetic operation may have the result overflow problem, if a B is very large, then the first sentence a=a+b will cause the result overflow, for example, the original a = 2147483647,b = 2, then the a+b is 2147483649, This number is greater than the largest unsigned integer 2147483648, so an overflow occurred, the result of a is actually: -2147483647, but surprisingly: although the first sentence of the result of the procedure is 2147483647, the latter two sentences get the result is correct, That is, to realize the exchange of the original A, a, or a value, that is to say: Only the result of the first sentence is wrong, but the final result is correct, this makes me very confused, has not yet made clear the reason, again to you for advice!
Finally, the advantages of this approach compared to the following scenario 2: The method can be used to exchange two non-integers (floating-point numbers), whereas scenario 2 is based on bit operations, and the floating-point numbers cannot be used directly, so scheme 2 cannot be used to exchange two floating-point numbers!
Scenario 2: Using bit arithmetic (better scheme)
The program code and scenario 1 and similar, the idea is not difficult, first look at the code, and then look at my wordy analysis:
[CPP]View Plaincopyprint?
- template<class t>
- void Myswap_2 (t& a,t& B)
- {
- A = A^b;
- b = b^a;
- A = A^b;
- }
Template<class t>void myswap_2 (t& a,t& b) { a = a^b; b = b^a; A = a^b;}
This switching function is no stranger to the programmer, but I believe some of these programmers have only remembered the code, and I don't know why the three lines of code are so, in fact, I did it initially, so I thought in the first place that it was just 3 line of code, so I took the time to understand the analysis, rather than the direct memory cost. In fact, until today I write this article, I would like to consume a little brain cells to understand it, below I try to explain the above three sentences, for convenience, suppose the data type is char, and a = 5,b=3; then in memory a A, a, is stored as follows:
Then analyze each sentence in detail:
First of all, the first sentence: a=a^b; After executing the statement, a and B are saved with a difference bit , that is, if the original A and b of a different, then the position of a is 1, so a in memory as the appearance, it shows A and b 2nd, 3 bit difference:
Then we look at the second sentence: B=b^a, which means to flip a bit that has a difference in B, so that the value saved in B is actually equal to the value in the original A, and remember that when the second statement finishes executing, a still retains the original, a, a, and B, and A is the original.
Finally, we look at the third sentence: a=a^b; Because the XOR operation satisfies the commutative law, this sentence is equivalent to: a=b^a; Remember that this statement assigns the value of B to the right of the original a value, and a has the original A, a, a and a, so the final function of this sentence is to reverse the difference in the original a bit ( to B) and assign to a so that the original B value is saved in a.
Summary: The above three sentences: the first sentence is the record difference, the 2nd, 3 sentence is flipped, finally realized without any intermediate variables on the exchange of two variables value.
Analysis: Bit operations do not consider carry problems, so there will be no problem with the result overflow! However, because the floating-point number cannot be operated directly, the method cannot realize the exchange of two floating-point numbers! The original title, of course, is the exchange of two integers.
Note: There are other ways to implement two-number exchange, such as using a memory copy! Because it does not belong to the category of bitwise operations, this is not mentioned here.
Bit Operations Application Example 2: binary conversion
Requirements: Implement decimal integers separately by binary, hexadecimal output.
Two methods are implemented by binary output:
Method 1: Since integers are stored on the computer in binary, we only need to print each bit sequentially, and if a bit is 1, print the character ' 1 ', otherwise print the character ' 0 '. The code I gave is as follows:
[CPP]View Plaincopyprint?
- voidprintbinary (int num)
- {
- For (int i=0;i<32;i++)
- {
- cout<< ((num>> (31-i)) &1);
- //cout<< (Num & (1<< (31-i)) ==0? 0:1);
- }
- }
voidprintbinary (int num) {for (int i=0;i<32;i++) { cout<< ((num>> (31-i)) &1); cout<< (Num & (1<< (31-i)) ==0? 0:1);} }
The cout that is commented out has the same function as the annotated cout! The idea of this function is simple, which is to print each bit from high to the bottom. My code above is a little bit bad, that is, the statement is too complex, a cout statement to do too many things, if it affects your understanding, then you can add a few temporary variables, and then split it into a number of simple statements. I am writing this mainly to account for the reasons for the length of the paragraph, so the procedure is too much space. Casually speaking, when programming, the statement to be simple and clear: a line only write a statement, a statement only do one thing!
Method Two: Using Bitset to realize
Bitset is a class (not a container) provided by the standard library, which makes it easy to manipulate bits, and the following is a program implemented with Bitset:
[CPP]View Plaincopyprint?
- voidprintbinary (int num)
- {
- bitset<32> bits =bitset< 32> ((Unsigned long) (num))
- for (int i=31;i>=0;i--)
- &NBSP;&NBSP;&NBSP;&NBSP;{&NBSP;&NBSP;
- cout<< (bits[i]==true? ' 1 ' :
- &NBSP;&NBSP;&NBSP;&NBSP;}
- }
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: About Bitset overloading multiple operators with the subscript operator: [], it is convenient to get a bit to see if it is 1. For more information on Bitset please refer to MSDN or other materials, just remember that Bitset is available in the standard library and you can always use it and don't forget to add the appropriate header file.
Implementation is output by 16:
Also because the data is stored in memory in binary, so the integer according to the 16 binary output we can do the following: From left to right, each 4 bit a group, combined into a hexadecimal number, once output, its program is as follows:
[CPP]View Plaincopyprint?
- void Printhex (int num)
- {
- For (inti=28;i>=0;i-=4)
- {
- int Temp =num>>i;
- Temp =temp&15; //15 is a mask!
- Char ch;
- Temp>9? (ch =' A ' +temp-10):(ch = ' 0 ' +temp);
- cout<<ch;
- }
- }
void printhex (int num) {for (inti=28;i>=0;i-=4) { int temp =num>>i; Temp =temp&15; 15 is a mask! Char ch; Temp>9? (ch = ' A ' +temp-10):(ch = ' 0 ' +temp); cout<<ch; } }
The program is very similar to the above printbinary function, it is important to note that I change 4 each time, the most important point is that the statement temp= temp&15; because it is 16 binary, so here with 15 mask. I want to have printbinary to do bedding, understand this printhex is not difficult, here do not repeat. Next I'll do a little expansion of these two functions: implementing Integers in 2n (2 of the n-th) binary output! For example, press 8 to enter, 32, and so on. For convenience of description, we limit 1<=n<=6; and use the characters ' 0 ' to ' 9 ' to denote numbers 0 to 9, with a character A, a, a,...... Z,a,b,...... Represents the number 10 to 63. The procedure is as follows:
[CPP]View Plaincopyprint?
- void Print2powern (int num,int N)
- {
- For (inti=32-n;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 ' +temp-10;
- }
- Else
- {
- ch = ' a ' +temp-36;
- }
- cout<<ch;
- }
- }
void Print2powern (int num,int N) {for (inti=32-n;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 ' +temp-10; } else { ch = ' a ' +temp-36; } cout<<ch; }}
Note: Using bit arithmetic can also realize the conversion of decimal to arbitrary, this problem is more difficult, I have not been thorough yet!
Bit Operation Case 3: The number of 1 in the binary representation of an integer
problem Description: input an integer n requires the output of the binary representation of the number of 1 m, such as n=13, then m=3;
Analysis: There is more than one method of solving this problem, which can be implemented for each bit-by-bit scan of binary representation, and the complexity of this method is O (n) where n is the total number of binary representations of N. Here is how to use bit operation to solve, and to ensure that its complexity is less than O (n), in fact, the complexity of the method is O (m), where m is n binary identification of 1 of the number!
idea: when it comes to concrete implementations, take a look at the fact thatn& (n-1) can turn the lowest bit 1 upside down! For example n=108, the second binary is represented as 01101100, then n& (n-1) results in 01101000. So as long as the minimum number of binary bits of n is constantly flipped to 1, each flip to let counter +1, until n equals 0 o'clock, the counter records n binary in the 1 bits, the program is as follows:
[CPP]View Plaincopyprint?
- int count1bits (long N)
- {
- int count = 0;
- While (n)
- {
- count++;
- N&= (n-1);
- }
- return count;
- }
int count1bits (long n) { int count =0; while (n) { count++; N&= (n-1); } return count;}
Note: For other methods of this issue, please refer to the beauty of programming. Another use of n& (n-1) is to determine whether N is an integer power of 2.
This is the end of this article, and I find that I have recently written something that I can say with a proverb: the binding of a lazy woman--smelly and long! There is no way, every time a want to write things, thinking very divergent (perhaps with a messy to describe more appropriate), it seems to be the big topic summary. Also, as a result of the recent hot weather, impetuous mood, dizzy, the code in the text has considered poor places, but also ask you to criticize.
Bit operation and its application example (1)