Search code examples
c++bit-manipulationbitwise-operatorsfunction-definition

Cyclic number shift to the right byte by byte


The program takes two numbers as input: num - a number for which a right cyclic shift must be performed byte by byte, and bytes - the number of bytes by which it must be shifted to the right.

The program works correctly only when shifting bytes for the value of 1. If asked to shift bytes for any other number, the output is not correct. What's wrong here?

unsigned long long shiftr(unsigned long long num, unsigned char bytes) {
    unsigned long long mask;
        switch (bytes)
        {
        case 1: 
            mask = 0xFF;
            break;
        case 2:
            mask = 0xFFFF;
            break;
        case 3:
            mask = 0xFFFFFF;
            break;
        case 4:
            mask = 0xFFFFFFFF;
            break;
        case 5:
            mask = 0xFFFFFFFFFF;
            break;
        case 6:
            mask = 0xFFFFFFFFFFFF;
            break;
        case 7:
            mask = 0xFFFFFFFFFFFFFF;
            break;
        case 8:
            mask = 0xFFFFFFFFFFFFFFFF;
            break;
        default:;
        }
        
        num = mask & ( ((num & 0x1) << (bytes * 8 - 1)) | (num >> 1) );
        return num;
}

With the value num = 1, the shift is performed correctly in all cases. But if you enter another number, the program will not work correctly. Why is that?


Solution

  • The expression used in this assignment statement

    num = mask & ( ((num & 0x1) << (bytes * 8 - 1)) | (num >> 1) );
    

    is wrong. For example this sub-expression (num & 0x1) extract only the first bit of the number that is shifted to the left while this sub-expression (num >> 1) moves the number to the right only by one bit.

    Also you need to check the value of the parameter bytes that is not greater than 8.

    Pay attention to that the parameter bytes specifies the number of bytes to shift not bits.

    Using your approach the function can look the following way as shown in the demonstration program below.

    #include <iostream>
    
    unsigned long long shiftr( unsigned long long num, unsigned char bytes )
    {
        const size_t N = sizeof( num );
    
        bytes %= N;
    
        if ( bytes != 0 )
        {
            unsigned long long  mask;
    
            switch (bytes)
            {
            case 1:
                mask = 0xFF;
                break;
            case 2:
                mask = 0xFFFF;
                break;
            case 3:
                mask = 0xFFFFFF;
                break;
            case 4:
                mask = 0xFFFFFFFF;
                break;
            case 5:
                mask = 0xFFFFFFFFFF;
                break;
            case 6:
                mask = 0xFFFFFFFFFFFF;
                break;
            case 7:
                mask = 0xFFFFFFFFFFFFFF;
                break;
            }
    
            num = ( mask & num ) << 8 * ( N - bytes ) | num >> 8 * bytes;
        }
    
        return num;
    }
    
    int main()
    {
        unsigned long long num = 0x123456789ABCDEF0;
    
        for (unsigned char bytes = 0; bytes < 8; ++bytes)
        {
            std::cout << std::hex << num << ": " << shiftr( num, bytes ) << '\n';
        }
    }
    

    The program output is

    123456789abcdef0: 123456789abcdef0
    123456789abcdef0: f0123456789abcde
    123456789abcdef0: def0123456789abc
    123456789abcdef0: bcdef0123456789a
    123456789abcdef0: 9abcdef012345678
    123456789abcdef0: 789abcdef0123456
    123456789abcdef0: 56789abcdef01234
    123456789abcdef0: 3456789abcdef012