Implementing Logical Right Shift in C

后端 未结 8 1021
心在旅途
心在旅途 2020-11-29 07:07

I\'m working on making a logical right shift function in C using only bitwise operators. Here\'s what I have:

int logical_right_shift(int x, int n)
{
    int         


        
相关标签:
8条回答
  • 2020-11-29 07:24

    This is what you need:

    int logical_right_shift(int x, int n)
    {
        int size = sizeof(int) * 8; // usually sizeof(int) is 4 bytes (32 bits)
        return (x >> n) & ~(((0x1 << size) >> n) << 1);
    }
    

    Explain

    x >> n shifts n bits right. However, if x is negative, the sign bit (left-most bit) will be copied to its right, for example:

    Assume every int is 32 bits here, let
    x     = -2147483648 (10000000 00000000 00000000 00000000), then
    x >> 1 = -1073741824 (11000000 00000000 00000000 00000000)
    x >> 2 = -536870912  (11100000 00000000 00000000 00000000)
    and so on.

    So we need to erase out those sign extra sign bits when n is negative.

    Assume n = 5 here:

    0x1 << size moves 1 to the left-most position:

    (10000000 00000000 00000000 00000000)

    ((0x1 << size) >> n) << 1 copies 1 to its n-1 neighbors:

    (11111000 00000000 00000000 00000000)

    ~((0x1 << size) >> n) << 1! reverses all bits:

    (00000111 11111111 11111111 11111111)

    so we finally obtain a mask to extract what really need from x >> n:

    (x >> n) & ~(((0x1 << size) >> n) << 1)
    

    the & operation does the trick.

    And the total cost of this function is 6 operations.

    0 讨论(0)
  • 2020-11-29 07:25

    I think problem is in your ">> (n-1)" part. If n is 0 then left part will be shift by -1. So,here is my solution

    int logical_right_shift(int x, int n)
    {
      int mask = ~(-1 << n) << (32 - n);
      return  ~mask & ( (x >> n) | mask); 
    }
    
    0 讨论(0)
  • 2020-11-29 07:25

    As with @Ignacio's comment, I don't know why you would want to do this (without just doing a cast to unsigned like in the other answers), but what about (assuming two's complement and binary, and that signed shifts are arithmetic):

    (x >> n) + ((1 << (sizeof(int) * CHAR_BIT - n - 1)) << 1)
    

    or:

    (x >> n) ^ ((INT_MIN >> n) << 1)
    
    0 讨论(0)
  • 2020-11-29 07:27

    Just store your int in an unsigned int, and perform >> upon it.

    (The sign is not extended or preserved if you use unsigned int)

    http://en.wikipedia.org/wiki/Logical_shift

    0 讨论(0)
  • 2020-11-29 07:29
    int lsr(int x, int n)
    {
      return (int)((unsigned int)x >> n);
    }
    
    0 讨论(0)
  • 2020-11-29 07:31

    Milnex's answer is great and has an awesome explanation, but the implementation unfortunately fails due to the shift by total size. Here is a working version:

    int logicalShift(int x, int n) {
      int totalBitsMinusOne = (sizeof(int) * 8) - 1; // usually sizeof(int) is 4 bytes (32 bits)
      return (x >> n) & ~(((0x1 << totalBitsMinusOne) >> n) << 1);
    }
    

    To have 1 as the most significant bit, and all zeroes elsewhere, we need to shift 0x1 by number of bits - 1. I am submitting my own answer because my edit to the accepted answer was somehow rejected.

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