Bitwise rotate left function

后端 未结 6 1476
一向
一向 2020-11-30 10:18

I am trying to implement a rotate left function that rotates an integer x left by n bits

  • Ex: rotateLeft(0x87654321,4) = 0x76543218
  • Legal ops: ~ &
相关标签:
6条回答
  • 2020-11-30 10:55

    The best way is:

    int rotateLeft(int x, int n)
    {
        _asm
        {
            mov eax, dword ptr [x]
            mov ecx, dword ptr [n]
            rol eax, cl
        }
    }
    

    If you need to rotate an int variable right in your code, then the fastest way is:

    #define rotl( val, shift ) _asm mov eax, dword ptr[val] _asm mov ecx, dword ptr [shift] _asm rol eax, cl _asm mov dword ptr [val], eax
    

    val is the value you rotate, shift is the length of the rotation.

    0 讨论(0)
  • 2020-11-30 10:55

    Can you define 'rotate left' for a signed int?

    I would simply cast x to an unsigned int and perform the rotation the way you have it right now.

    On another note: does your code need to work on different architectures (not just 32-bit)? You may want to avoid hardcoding the int bitsize.

    0 讨论(0)
  • 2020-11-30 11:02

    I find a way for doing a rotate that can be useful when you work with some bit who the size is fixed and you knew it:

    int rotate_bit_left(int bit_rotating){
     int LastMax = 64;
     bit_rotating = (bit_rotating>=LastMax)? ((bit_rotating << 1 ) | 0x01) : bit_rotating << 1 ;
     return bit_rotating;
     /*
      Here LastMax is 64 because in the exemple I work in the Ascii table where the max is 0111 1111 and this value can be adapted with the value of the last one bit in decimale
     */
    }
    

    This function can be changed to a right rotate

    int rotate_bit_right(int bit_rotating){
     bit_rotating = ((bit_rotating%2)==1)? ((bit_rotating >> 1)| 0x80 ): bit_rotating >> 1 ;
     return bit_rotating; 
     /*
     Because if is a odd number then the last bit is one and we have to put it in the first place
     */
    }
    

    Notice that 0x01 and 0x80 must be changed if your worked in an other case than Ascii table to Hexa number with a pattern like this : 0...0001 for the left rotate 100....0 for the right rotate

    0 讨论(0)
  • 2020-11-30 11:04
    int rotateLeft(int x, int n) {
      return (x << n) | (x >> (32 - n)) & ~((-1 >> n) << n);
    }
    

    UPDATE:(thanks a lot @George)

    int rotateLeft(int x, int n) {
      return (x << n) | (x >> (32 - n)) & ~(-1 << n);
    }
    

    not use '-' version.

    int rotateLeft(int x, int n) {
        return (x << n) | (x >> (0x1F & (32 + ~n + 1))) & ~(0xFFFFFFFF << n);
    }
    
    //test program
    int main(void){
        printf("%x\n",rotateLeft(0x87654321,4));
        printf("%x\n",rotateLeft(0x87654321,8));
        printf("%x\n",rotateLeft(0x80000000,1));
        printf("%x\n",rotateLeft(0x78123456,4));
        printf("%x\n",rotateLeft(0xFFFFFFFF,4));
        return 0;
    }
    /* result : GCC 4.4.3 and Microsoft(R) 32-bit C 16.00.40219.01
    76543218
    65432187
    1
    81234567
    ffffffff
    */
    
    0 讨论(0)
  • 2020-11-30 11:06

    Current best practice for compiler-friendly rotates is this community-wiki Q&A. The code from wikipedia doesn't produce very good asm with clang, or gcc older than 5.1.

    There's a very good, detailed explanation of bit rotation a.k.a. circular shift on Wikipedia.

    Quoting from there:

    unsigned int _rotl(const unsigned int value, int shift) {
        if ((shift &= sizeof(value)*8 - 1) == 0)
          return value;
        return (value << shift) | (value >> (sizeof(value)*8 - shift));
    }
    
    unsigned int _rotr(const unsigned int value, int shift) {
        if ((shift &= sizeof(value)*8 - 1) == 0)
          return value;
        return (value >> shift) | (value << (sizeof(value)*8 - shift));
    

    In your case, since you don't have access to the multiplication operator, you can replace *8 with << 3.

    EDIT You can also remove the if statements given your statement that you cannot use if. That is an optimization, but you still get the correct value without it.

    Note that, if you really intend to rotate bits on a signed integer, the interpretation of the rotated result will be platform dependent. Specifically, it will depend on whether the platform uses Two's Complement or One's Complement. I can't think of an application where it is meaningful to rotate the bits of a signed integer.

    0 讨论(0)
  • 2020-11-30 11:13

    In ISO C (no idea if this is your implementation language or not, but it sure looks like it), shift-right on a signed integer that’s negative is implementation-defined and should thus be avoided.

    If you’re doing bitops anyway, you really should cast to unsigned integers first.

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