What are bitwise shift (bit-shift) operators and how do they work?

后端 未结 11 1474
生来不讨喜
生来不讨喜 2020-11-21 04:46

I\'ve been attempting to learn C in my spare time, and other languages (C#, Java, etc.) have the same concept (and often the same operators) ...

What I\'m wondering

相关标签:
11条回答
  • 2020-11-21 05:02

    The bitwise shift operators move the bit values of a binary object. The left operand specifies the value to be shifted. The right operand specifies the number of positions that the bits in the value are to be shifted. The result is not an lvalue. Both operands have the same precedence and are left-to-right associative.

    Operator     Usage
    
     <<           Indicates the bits are to be shifted to the left.
    
     >>           Indicates the bits are to be shifted to the right.
    

    Each operand must have an integral or enumeration type. The compiler performs integral promotions on the operands, and then the right operand is converted to type int. The result has the same type as the left operand (after the arithmetic conversions).

    The right operand should not have a negative value or a value that is greater than or equal to the width in bits of the expression being shifted. The result of bitwise shifts on such values is unpredictable.

    If the right operand has the value 0, the result is the value of the left operand (after the usual arithmetic conversions).

    The << operator fills vacated bits with zeros. For example, if left_op has the value 4019, the bit pattern (in 16-bit format) of left_op is:

    0000111110110011
    

    The expression left_op << 3 yields:

    0111110110011000
    

    The expression left_op >> 3 yields:

    0000000111110110
    
    0 讨论(0)
  • 2020-11-21 05:04

    I am writing tips and tricks only. It may be useful in tests and exams.

    1. n = n*2: n = n<<1
    2. n = n/2: n = n>>1
    3. Checking if n is power of 2 (1,2,4,8,...): check !(n & (n-1))
    4. Getting xth bit of n: n |= (1 << x)
    5. Checking if x is even or odd: x&1 == 0 (even)
    6. Toggle the nth bit of x: x ^ (1<<n)
    0 讨论(0)
  • 2020-11-21 05:08

    Bitwise operations, including bit shift, are fundamental to low-level hardware or embedded programming. If you read a specification for a device or even some binary file formats, you will see bytes, words, and dwords, broken up into non-byte aligned bitfields, which contain various values of interest. Accessing these bit-fields for reading/writing is the most common usage.

    A simple real example in graphics programming is that a 16-bit pixel is represented as follows:

      bit | 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1  | 0 |
          |       Blue        |         Green         |       Red          |
    

    To get at the green value you would do this:

     #define GREEN_MASK  0x7E0
     #define GREEN_OFFSET  5
    
     // Read green
     uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;
    

    Explanation

    In order to obtain the value of green ONLY, which starts at offset 5 and ends at 10 (i.e. 6-bits long), you need to use a (bit) mask, which when applied against the entire 16-bit pixel, will yield only the bits we are interested in.

    #define GREEN_MASK  0x7E0
    

    The appropriate mask is 0x7E0 which in binary is 0000011111100000 (which is 2016 in decimal).

    uint16_t green = (pixel & GREEN_MASK) ...;
    

    To apply a mask, you use the AND operator (&).

    uint16_t green = (pixel & GREEN_MASK) >> GREEN_OFFSET;
    

    After applying the mask, you'll end up with a 16-bit number which is really just a 11-bit number since its MSB is in the 11th bit. Green is actually only 6-bits long, so we need to scale it down using a right shift (11 - 6 = 5), hence the use of 5 as offset (#define GREEN_OFFSET 5).

    Also common is using bit shifts for fast multiplication and division by powers of 2:

     i <<= x;  // i *= 2^x;
     i >>= y;  // i /= 2^y;
    
    0 讨论(0)
  • 2020-11-21 05:09

    The Bitwise operators are used to perform operations a bit-level or to manipulate bits in different ways. The bitwise operations are found to be much faster and are some times used to improve the efficiency of a program. Basically, Bitwise operators can be applied to the integer types: long, int, short, char and byte.

    Bitwise Shift Operators

    They are classified into two categories left shift and the right shift.

    • Left Shift(<<): The left shift operator, shifts all of the bits in value to the left a specified number of times. Syntax: value << num. Here num specifies the number of position to left-shift the value in value. That is, the << moves all of the bits in the specified value to the left by the number of bit positions specified by num. For each shift left, the high-order bit is shifted out (and ignored/lost), and a zero is brought in on the right. This means that when a left shift is applied to 32-bit compiler, bits are lost once they are shifted past bit position 31. If the compiler is of 64-bit then bits are lost after bit position 63.

    Output: 6, Here the binary representation of 3 is 0...0011(considering 32-bit system) so when it shifted one time the leading zero is ignored/lost and all the rest 31 bits shifted to left. And zero is added at the end. So it became 0...0110, the decimal representation of this number is 6.

    • In the case of a negative number:

    Output: -2, In java negative number, is represented by 2's complement. SO, -1 represent by 2^32-1 which is equivalent to 1....11(Considering 32-bit system). When shifted one time the leading bit is ignored/lost and the rest 31 bits shifted to left and zero is added at the last. So it becomes, 11...10 and its decimal equivalent is -2. So, I think you get enough knowledge about the left shift and how its work.

    • Right Shift(>>): The right shift operator, shifts all of the bits in value to the right a specified of times. Syntax: value >> num, num specifies the number of positions to right-shift the value in value. That is, the >> moves/shift all of the bits in the specified value of the right the number of bit positions specified by num. The following code fragment shifts the value 35 to the right by two positions:

    Output: 8, As a binary representation of 35 in a 32-bit system is 00...00100011, so when we right shift it two times the first 30 leading bits are moved/shifts to the right side and the two low-order bits are lost/ignored and two zeros are added at the leading bits. So, it becomes 00....00001000, the decimal equivalent of this binary representation is 8. Or there is a simple mathematical trick to find out the output of this following code: To generalize this we can say that, x >> y = floor(x/pow(2,y)). Consider the above example, x=35 and y=2 so, 35/2^2 = 8.75 and if we take the floor value then the answer is 8.

    Output:

    But remember one thing this trick is fine for small values of y if you take the large values of y it gives you incorrect output.

    • In the case of a negative number: Because of the negative numbers the Right shift operator works in two modes signed and unsigned. In signed right shift operator (>>), In case of a positive number, it fills the leading bits with 0. And In case of a negative number, it fills leading bits with 1. To keep the sign. This is called 'sign extension'.

    Output: -5, As I explained above the compiler stores the negative value as 2's complement. So, -10 is represented as 2^32-10 and in binary representation considering 32-bit system 11....0110. When we shift/ move one time the first 31 leading bits got shifted in the right side and the low-order bit got lost/ignored. So, it becomes 11...0011 and the decimal representation of this number is -5 (How I know the sign of number? because the leading bit is 1). It is interesting to note that if you shift -1 right, the result always remains -1 since sign extension keeps bringing in more ones in the high-order bits.

    • Unsigned Right Shift(>>>): This operator also shifts bits to the right. The difference between signed and unsigned is the latter fills the leading bits with 1 if the number is negative and the former fills zero in either case. Now the question arises why we need unsigned right operation if we get the desired output by signed right shift operator. Understand this with an example, If you are shifting something that does not represent a numeric value, you may not want sign extension to take place. This situation is common when you are working with pixel-based values and graphics. In these cases, you will generally want to shift a zero into the high-order bit no matter what it's the initial value was.

    Output: 2147483647, Because -2 is represented as 11...10 in a 32-bit system. When we shift the bit by one, the first 31 leading bit is moved/shifts in right and the low-order bit is lost/ignored and the zero is added to the leading bit. So, it becomes 011...1111 (2^31-1) and its decimal equivalent is 2147483647.

    0 讨论(0)
  • 2020-11-21 05:11

    Be aware of that only 32 bit version of PHP is available on the Windows platform.

    Then if you for instance shift << or >> more than by 31 bits, results are unexpectable. Usually the original number instead of zeros will be returned, and it can be a really tricky bug.

    Of course if you use 64 bit version of PHP (Unix), you should avoid shifting by more than 63 bits. However, for instance, MySQL uses the 64-bit BIGINT, so there should not be any compatibility problems.

    UPDATE: From PHP 7 Windows, PHP builds are finally able to use full 64 bit integers: The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18, except on Windows prior to PHP 7, where it was always 32 bit.

    0 讨论(0)
提交回复
热议问题