Поворот влево по переменной без переноса? - PullRequest
1 голос
/ 08 апреля 2011

Давайте поставим задачу выполнить вращение влево-вправо для переменной a без переноса в C ++. Я думаю, что было бы намного лучше использовать ассемблер, чтобы выполнить эту процедуру, не так ли?

Например, если у нас есть a == 100 == 0b<a bunch of zeros>1100100, a LR 1 должен предоставить 0b1001001 == 73 (т.е. не 0b11001000 == 200).

Итак, вопрос в : как следует переписать приведенный ниже код для соответствия приведенной выше задаче?

#include <stdio.h>

int main()
{
  long long a = 0;

  scanf("%ld", &a);

  // Here the left-shifting should be replaced with left-rotating
  printf("%ld\n", a << 1);

  return 0;
}

Ответы [ 3 ]

3 голосов
/ 08 апреля 2011

Shift-with-carry не имеет смысла в языке высокого уровня (даже C), потому что нет способа прочитать флаг переноса (ранее старший бит) из таких языков, кроме более встроенной сборки.

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


Глядя на ваш исправленный вопрос, операция, которую вы пытаетесь выполнить, совершенно не связана с какой-либо инструкцией сдвига с переносом, доступной на распространенных процессорах. Поскольку вы хотите сдвинуться на единицу, а затем очистить старший значащий бит, может оказаться полезной инструкция bsr, многие компиляторы имеют встроенных функций , которые предоставляют вам доступ к этой инструкции из кода C.

3 голосов
/ 08 апреля 2011

Конечно, было бы не лучше выполнить встроенную сборку, чтобы сделать что-то столь же простое, как сдвиг влево с переносом. Любой современный компилятор легко справится с этим и создаст эквивалентную сборку для всего, что вы написали от руки, плюс преимущество в том, что вы не станете зависимым от платформы.

1 голос
/ 08 апреля 2011

Если вы действительно хотите ассемблер, то вот как может выглядеть поворот левой 64-битной переменной на один бит в Visual C ++ (для GCC __asm ​​отличается). Для сравнения есть также реализация в C ++. Конечно, это 32-битный ассемблер.

unsigned long long rotate_left_64(unsigned long long n)
{  
    return (n << 1) | (n >> 63);
}

int main()
{
    unsigned long long a = 0xF0F0F0F0F0F0F0F0;

    std::cout << std::hex << rotate_left_64(a) << std::endl;

    __asm
    {
        lea ebx, a
        rol DWORD PTR [ebx], 1
        rcl DWORD PTR [ebx+4], 1
    }
    std::cout << std::hex << a << std::endl;
    return 0;
}
...