Best practices for circular shift (rotate) operations in C++

前端 未结 16 1583
情深已故
情深已故 2020-11-22 00:09

Left and right shift operators (<< and >>) are already available in C++. However, I couldn\'t find out how I could perform circular shift or rotate operations.

相关标签:
16条回答
  • 2020-11-22 00:37

    How abt something like this, using the standard bitset ...

    #include <bitset> 
    #include <iostream> 
    
    template <std::size_t N> 
    inline void 
    rotate(std::bitset<N>& b, unsigned m) 
    { 
       b = b << m | b >> (N-m); 
    } 
    
    int main() 
    { 
       std::bitset<8> b(15); 
       std::cout << b << '\n'; 
       rotate(b, 2); 
       std::cout << b << '\n'; 
    
       return 0;
    }
    

    HTH,

    0 讨论(0)
  • 2020-11-22 00:39

    another suggestion

    template<class T>
    inline T rotl(T x, unsigned char moves){
        unsigned char temp;
        __asm{
            mov temp, CL
            mov CL, moves
            rol x, CL
            mov CL, temp
        };
        return x;
    }
    
    0 讨论(0)
  • 2020-11-22 00:39

    Below is a slightly improved version of Dídac Pérez's answer, with both directions implemented, along with a demo of these functions' usages using unsigned char and unsigned long long values. Several notes:

    1. The functions are inlined for compiler optimizations
    2. I used a cout << +value trick for tersely outputting an unsigned char numerically that I found here: https://stackoverflow.com/a/28414758/1599699
    3. I recommend using the explicit <put the type here> syntax for clarity and safety.
    4. I used unsigned char for the shiftNum parameter because of what I found in the Additional Details section here:

    The result of a shift operation is undefined if additive-expression is negative or if additive-expression is greater than or equal to the number of bits in the (promoted) shift-expression.

    Here's the code I'm using:

    #include <iostream>
    
    using namespace std;
    
    template <typename T>
    inline T rotateAndCarryLeft(T rotateMe, unsigned char shiftNum)
    {
        static const unsigned char TBitCount = sizeof(T) * 8U;
    
        return (rotateMe << shiftNum) | (rotateMe >> (TBitCount - shiftNum));
    }
    
    template <typename T>
    inline T rotateAndCarryRight(T rotateMe, unsigned char shiftNum)
    {
        static const unsigned char TBitCount = sizeof(T) * 8U;
    
        return (rotateMe >> shiftNum) | (rotateMe << (TBitCount - shiftNum));
    }
    
    void main()
    {
        //00010100 == (unsigned char)20U
        //00000101 == (unsigned char)5U == rotateAndCarryLeft(20U, 6U)
        //01010000 == (unsigned char)80U == rotateAndCarryRight(20U, 6U)
    
        cout << "unsigned char " << 20U << " rotated left by 6 bits == " << +rotateAndCarryLeft<unsigned char>(20U, 6U) << "\n";
        cout << "unsigned char " << 20U << " rotated right by 6 bits == " << +rotateAndCarryRight<unsigned char>(20U, 6U) << "\n";
    
        cout << "\n";
    
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned char) * 8U; ++shiftNum)
        {
            cout << "unsigned char " << 21U << " rotated left by " << +shiftNum << " bit(s) == " << +rotateAndCarryLeft<unsigned char>(21U, shiftNum) << "\n";
        }
    
        cout << "\n";
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned char) * 8U; ++shiftNum)
        {
            cout << "unsigned char " << 21U << " rotated right by " << +shiftNum << " bit(s) == " << +rotateAndCarryRight<unsigned char>(21U, shiftNum) << "\n";
        }
    
    
        cout << "\n";
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned long long) * 8U; ++shiftNum)
        {
            cout << "unsigned long long " << 3457347ULL << " rotated left by " << +shiftNum << " bit(s) == " << rotateAndCarryLeft<unsigned long long>(3457347ULL, shiftNum) << "\n";
        }
    
        cout << "\n";
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned long long) * 8U; ++shiftNum)
        {
            cout << "unsigned long long " << 3457347ULL << " rotated right by " << +shiftNum << " bit(s) == " << rotateAndCarryRight<unsigned long long>(3457347ULL, shiftNum) << "\n";
        }
    
        cout << "\n\n";
        system("pause");
    }
    
    0 讨论(0)
  • 2020-11-22 00:40
    #define ROTATE_RIGHT(x) ( (x>>1) | (x&1?0x8000:0) )
    
    0 讨论(0)
  • 2020-11-22 00:41

    Assuming you want to shift right by L bits, and the input x is a number with N bits:

    unsigned ror(unsigned x, int L, int N) 
    {
        unsigned lsbs = x & ((1 << L) - 1);
        return (x >> L) | (lsbs << (N-L));
    }
    
    0 讨论(0)
  • 2020-11-22 00:44

    Since it's C++, use an inline function:

    template <typename INT> 
    INT rol(INT val) {
        return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
    }
    

    C++11 variant:

    template <typename INT> 
    constexpr INT rol(INT val) {
        static_assert(std::is_unsigned<INT>::value,
                      "Rotate Left only makes sense for unsigned types");
        return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
    }
    
    0 讨论(0)
提交回复
热议问题