按位旋转(循环移位)

时间:2014-09-12 01:06:13

标签: c++ bit-manipulation

我试图在C ++中创建一些关于“按位旋转”的代码,我想通过左边的shif来做这个。我不知道如何编写代码,但我在“维基百科”中找到了一些像这样的代码。

unsigned int rotl(unsigned int value, int shift) {
return (value << shift) | (value >> (sizeof(value) * CHAR_BIT - shift));
}

然后我试着让它工作,但是这段代码没有给出我期望的输出。防爆。我有二进制1100中的数字unsigned int 12,当我想通过左上方用上面的代码进行按位旋转时,输出是和unsigned int 24,(11000),它必须给出输出unsigned int 9,因为如果我进行按位旋转(左shif),第一个MSB位现在必须是第一位,而所有其他位必须向左移动一位。

你能帮助理解这个问题是什么吗?或者我做错了什么。

谢谢。

6 个答案:

答案 0 :(得分:6)

以下代码效果很好

#include <cstdint>

std::uint32_t rotl(std::uint32_t v, std::int32_t shift) {
    std::int32_t s =  shift>=0? shift%32 : -((-shift)%32);
    return (v<<s) | (v>>(32-s));
}

std::uint32_t rotr(std::uint32_t v, std::int32_t shift) {
    std::int32_t s =  shift>=0? shift%32 : -((-shift)%32);
    return (v>>s) | (v<<(32-s));
}

当然还有它的测试。

#include <iostream>

int main(){
   using namespace std;
   cout<<rotr(8,1)<<endl; // 4
   cout<<rotr(8,-1)<<endl;  //16
   cout<<rotl(8,1)<<endl;  //16
   cout<<rotl(8,-1)<<endl;  //4
   cout<<rotr(4,60)<<endl;  //64
   cout<<rotr(4,61)<<endl; //32
   cout<<rotl(4,3)<<endl;  //32
   cout<<rotl(4,4)<<endl;  //64
   return 0;
}

也许我没有提供最快的实现,但肯定是便携式和稳定的

通用版

#include <cstdint>

template< class T>
inline T rotl( T v, std::int32_t shift){
    std::size_t m = sizeof(v)*std::numeric_limits<T>::digits;
    T s = shift>=0? shift%m: -((-shift)%m)
    return (v<<s) | (v>>(m-s));
}

template< class T>
inline T rotr( T v, std::int32_t shift){
    std::size_t m = sizeof(v)*std::numeric_limits<T>::digits;
    T s = shift>=0? shift%m: -((-shift)%m)
    return (v>>s) | (v<<(m-s));
}

干杯:)

答案 1 :(得分:1)

C ++ 20在std::rotl标头中提供std::rotr<bit>。来自cppreference.com的示例:

#include <bit>
#include <bitset>
#include <cstdint>
#include <iostream>

int main()
{
    std::uint8_t i = 0b00011101;
    std::cout << "i          = " << std::bitset<8>(i) << '\n';
    std::cout << "rotl(i,0)  = " << std::bitset<8>(std::rotl(i,0)) << '\n';
    std::cout << "rotl(i,1)  = " << std::bitset<8>(std::rotl(i,1)) << '\n';
    std::cout << "rotl(i,4)  = " << std::bitset<8>(std::rotl(i,4)) << '\n';
    std::cout << "rotl(i,9)  = " << std::bitset<8>(std::rotl(i,9)) << '\n';
    std::cout << "rotl(i,-1) = " << std::bitset<8>(std::rotl(i,-1)) << '\n';
}

我相信std::bitset仅在本示例中用于其流格式。

答案 2 :(得分:0)

这是因为您使用了32位的int,所以它通过将最高有效位包装到前面而按预期工作。使用较小的数据结构(如unsigned char)可以使其更易于管理。

答案 3 :(得分:0)

整数中有4位以上,很可能是32位,但理论上可能是64或16.所以12位的值是00000000000000000000000000001100。左旋转1会自然给你00000000000000000000000000011000(= 24)。

答案 4 :(得分:0)

如果你想在任意数量的位上进行按位旋转(例如4),只需在你的函数中添加一个参数:

unsigned int rotl(unsigned int value, int shift, unsigned int width) {
    return ((value << shift) & (UINT_MAX >> (sizeof(int) * CHAR_BIT - width))) | (value >> (width - shift));
}

答案 5 :(得分:-1)

如果您不使用 C++20,您可能需要两个辅助函数,例如:

template< std::size_t N >
[[ nodiscard ]] std::bitset< N > rotl( std::bitset< N > b, std::size_t const n ) noexcept
{
    return b << n | b >> ( N - n );
}

template< std::size_t N >
[[ nodiscard ]] std::bitset< N > rotr( std::bitset< N > b, std::size_t const n ) noexcept
{
    return b >> n | b << ( N - n );
}

并像使用 C++20 的 std::rotlstd::rotr 一样使用它们。