Лучшие практики для операций кругового сдвига (поворота) в C ++ - PullRequest
79 голосов
/ 22 апреля 2009

Операторы сдвига влево и вправо (<< и >>) уже доступны в C ++. Однако я не мог выяснить, как я мог выполнять операции кругового сдвига или поворота.

Как можно выполнять такие операции, как «Поворот влево» и «Поворот вправо»?

Здесь дважды вращается вправо

Initial --> 1000 0011 0100 0010

должно привести к:

Final   --> 1010 0000 1101 0000

Пример будет полезен.

(примечание редактора: многие распространенные способы выражения поворотов в C страдают от неопределенного поведения, если счетчик поворотов равен нулю или компилируется в более чем одну машинную инструкцию поворота. Ответ на этот вопрос должен задокументировать лучшие практики)

Ответы [ 15 ]

0 голосов
/ 13 июня 2015

Ниже приведена слегка улучшенная версия Ответ Дидака Переса , в котором реализованы оба направления, а также демонстрация использования этих функций с использованием unsigned char и unsigned long long. Несколько заметок:

  1. Функции встроены для оптимизации компилятора
  2. Я использовал трюк cout << +value для краткого вывода числового знака без знака, который нашел здесь: https://stackoverflow.com/a/28414758/1599699
  3. Я рекомендую использовать явный синтаксис <put the type here> для ясности и безопасности.
  4. Я использовал unsigned char для параметра shiftNum из-за того, что нашел в разделе «Дополнительные сведения» здесь :

Результат операции сдвига не определен, если добавочное выражение равно отрицательный или если аддитивное выражение больше или равно количество бит в (повышенном) выражении смещения .

Вот код, который я использую:

#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 голосов
/ 16 ноября 2013

другое предложение

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 голосов
/ 31 октября 2013

Исходный код х бит номер

int x =8;
data =15; //input
unsigned char tmp;
for(int i =0;i<x;i++)
{
printf("Data & 1    %d\n",data&1);
printf("Data Shifted value %d\n",data>>1^(data&1)<<(x-1));
tmp = data>>1|(data&1)<<(x-1);
data = tmp;  
}
0 голосов
/ 22 апреля 2009

Перегрузка функции:

unsigned int rotate_right(unsigned int x)
{
 return (x>>1 | (x&1?0x80000000:0))
}

unsigned short rotate_right(unsigned short x) { /* etc. */ }
0 голосов
/ 22 апреля 2009
#define ROTATE_RIGHT(x) ( (x>>1) | (x&1?0x8000:0) )
...