8

I was trying to make some code in C++ about “bitwise rotation” and I would like to make this by the left shif. I didn’t know how to code this, but I found a little code in “Wikipedia” like this.

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

Then I tried to make it work, but this code don’t give the output that I expected. Ex. I have the number unsigned int 12, in binary 1100, and when I want to do bitwise rotation by the left shif with the code above, the output is and unsigned int 24,( 11000), and it had to give the output unsigned int 9, because if I make the bitwise rotation(left shif), the first MSB bit have to be now the first bit, and all the others bits have to move one bit to left.

Can you help to understand what is the problem of that ?, or if I am doing something wrong.

Thank you.

NutCracker
  • 9,614
  • 2
  • 36
  • 62
user3721105
  • 75
  • 1
  • 1
  • 5
  • So your value is 4 bits wide? The code you have shown works for a value of type `unsigned int`, which is much more than 4 bits. – Greg Hewgill Sep 12 '14 at 01:10
  • your function is correct. An integer has 32 bits, not 4. – chuck1 Sep 12 '14 at 01:10
  • @GregHewgill You are talking about "classical rotating shift", but OP asks for a different thing. It could be misunderstanding what "circular shift" means. – AlexD Sep 12 '14 at 01:11
  • what's your definition for CHAR_BIT, I test it with 8 ,it outputs 24 – michaeltang Sep 12 '14 at 01:13
  • The function looks OK and implements circular shift (as it is commonly understood). I.e. if you shift a number by 1, bit `31` goes to position `0`, regardless of its value. What you are expecting and illustrating in your sample, is something totally different. – AlexD Sep 12 '14 at 01:21
  • If you recursively call `rotl` using your initial input (12), what are you expecting to get? Classical rotation gets you `12->24->48->...->3221225472->2147483649->3->6->12...`. One interpretation of your assumed answer could be `12->9->3->6->12...` but another could be `12->9->3->3->3...`. – MooseBoys Sep 12 '14 at 01:29
  • would you show us your code, i was wondering how did you get 9 – michaeltang Sep 12 '14 at 01:30
  • I added a working implementation, it has also a test showing its working great and is totally branchless :) – CoffeDeveloper Sep 12 '14 at 02:15
  • possible duplicate of [Circular shift operations in C++](http://stackoverflow.com/questions/776508/circular-shift-operations-in-c) – CoffeDeveloper Sep 12 '14 at 02:20
  • there's no type less than 8 bits in C/C++ and if you want to rotate only 4 bits you must explicitly handle that case. The rotating instructions in CPU always rotate the whole register, not part of it – phuclv Sep 12 '14 at 03:45

6 Answers6

6

Following code works great

#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));
}

and of course the test for it.

#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;
}

maybe I not provided the fastest implementation, but a portable and stable one for sure

Generic version

#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));
}

Cheers :)

CoffeDeveloper
  • 6,929
  • 2
  • 31
  • 58
  • forgot "#include " and have to remove "sizeof(v)" in the generic version of code (was using CHAR_BITS). Free points for any editer. I can hardly figure a faster version without using assembly instructions – CoffeDeveloper Sep 12 '14 at 02:27
1

C++20 provides std::rotl and std::rotr in the <bit> header. An example from 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';
}

I believe std::bitset is only used in this example for its stream formatting.

leo60228
  • 429
  • 6
  • 17
0

It's because you're using an int which is 32 bits, so it worked as expected by wrapping the most significant bits to the front. Use a smaller data structure like an unsigned char to make this more managable.

Dan
  • 1,742
  • 1
  • 15
  • 20
0

You have more than 4 bits in your integer, most likely 32, but could theoretically be 64 or 16. So your bits for the value 12 are 00000000000000000000000000001100. Doing a left rotation by 1 would naturally give you the value 00000000000000000000000000011000 (=24).

0

if you want bitwise rotation over an arbitrary number of bits (for example 4), simply add a parameter to your function:

unsigned int rotl(unsigned int value, int shift, unsigned int width) {
    return ((value << shift) & (UINT_MAX >> (sizeof(int) * CHAR_BIT - width))) | (value >> (width - shift));
}
chuck1
  • 453
  • 4
  • 18
  • You also need to mask the answer to the proper number of bits. And I think your formula is slightly off too. – Mark Ransom Sep 12 '14 at 01:40
  • 1
    The `* CHAR_BIT` is wrong here, assuming that `width` is in bits, not bytes. You mean: `return ((1U << width) - 1) & ((value << shift) | (value >> (width - shift)));`. – Carlo Wood Sep 12 '14 at 01:50
  • The `if` test should be `if (width > sizeof(value) * CHAR_BIT)`, but it seems that that is implied. No need to add that branch there, it would make this a **lot** slower than needed. – Carlo Wood Sep 12 '14 at 01:57
-1

If you don't use C++20, you may want to have two helper functions like:

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 );
}

and use them the same as you would use C++20's std::rotl and std::rotr.

NutCracker
  • 9,614
  • 2
  • 36
  • 62