A la izquierda y a la derecha operadores de desplazamiento (<< y >>) ya están disponibles en C++.
Sin embargo, no pude averiguar cómo podía realizar la circular de cambio o rotación de operaciones.

¿Cómo pueden las operaciones como «Girar a la Izquierda» y «Girar a la Derecha» se realiza?

Rotación a la derecha dos veces aquí

Initial --> 1000 0011 0100 0010

debe resultar en:

Final   --> 1010 0000 1101 0000

Un ejemplo podría ser útil.

(nota del editor: Muchas de las formas de expresión de la gira en C sufren de un comportamiento indefinido si la rotación número es cero, o compilar para algo más que un solo girar una instrucción de máquina. Esta pregunta la respuesta debe documentar las mejores prácticas.)

16 Comentarios

  1. 91

    Ver también una versión anterior de esta respuesta en otro rotar pregunta, con algunos detalles más acerca de lo que asm gcc/clang producir para la arquitectura x86.

    La mayoría de compilador de usar para expresar un girar en C y C++ que evita cualquier Indefinido Comportamiento parece ser Juan Regehr de la aplicación. Me he adaptado a girar por el ancho de la tipo (uso de ancho fijo de tipos como uint32_t).

    #include <stdint.h>   //for uint32_t
    #include <limits.h>   //for CHAR_BIT
    //#define NDEBUG
    #include <assert.h>
    
    static inline uint32_t rotl32 (uint32_t n, unsigned int c)
    {
      const unsigned int mask = (CHAR_BIT*sizeof(n) - 1);  //assumes width is a power of 2.
    
      //assert ( (c<=mask) &&"rotate by type width or more");
      c &= mask;
      return (n<<c) | (n>>( (-c)&mask ));
    }
    
    static inline uint32_t rotr32 (uint32_t n, unsigned int c)
    {
      const unsigned int mask = (CHAR_BIT*sizeof(n) - 1);
    
      //assert ( (c<=mask) &&"rotate by type width or more");
      c &= mask;
      return (n>>c) | (n<<( (-c)&mask ));
    }

    Funciona para cualquier tipo de entero sin signo, no sólo uint32_t, así que usted podría hacer versiones para otros tamaños.

    Ver también un C++11 versión de la plantilla con un montón de controles de seguridad (incluyendo un static_assert que el tipo de ancho es una potencia de 2), que no es el caso en algunos de 24-bit Dsp o 36 bits mainframes, por ejemplo.

    Me gustaría recomendar sólo utilizando la plantilla como un back-end para contenedores con nombres que incluyen la rotación de ancho de forma explícita. Entero-las reglas de la promoción significa que rotl_template(u16 & 0x11UL, 7) haría una versión de 32 o de 64 bits de girar, no 16 (dependiendo de la anchura de unsigned long). Incluso uint16_t & uint16_t es promovido a signed int por C++entero-las reglas de la promoción, excepto en las plataformas donde int es ni más de uint16_t.


    En x86, esta versión elementos incorporados a un único rol r32, cl (o rol r32, imm8) con compiladores que grok, porque el compilador sabe que x86 rotar y cambiar las instrucciones máscara de el cambio-el recuento de la misma manera el código fuente en C no.

    Soporte para el compilador de este UB-evitar el lenguaje en x86, para uint32_t x y unsigned int n para la variable de conteo de cambios:

    • clang: reconocida para la variable de conteo de gira desde clang3.5, varios turnos+o insns antes de que.
    • gcc: reconocido por la variable de conteo de gira desde gcc4.9, varios turnos+o insns antes de que. gcc5 y más tarde optimizar la distancia de la rama y la máscara en la wikipedia versión, también, con sólo un ror o rol instrucción para la variable cuenta.
    • icc: soportados para la variable de conteo de gira desde ICC13 o anterior. La constante de contar gira uso shld edi,edi,7 que es más lento y requiere más bytes de los rol edi,7 en algunas Cpu (especialmente los de AMD, pero también algunos de Intel), cuando BMI2 no está disponible para rorx eax,edi,25 para guardar un MOV.
    • MSVC: x86-64 CL19: Sólo reconocido por la constante de recuento de gira. (La wikipedia modismo es reconocido, pero la rama y no optimizado de distancia). El uso de la _rotl /_rotr de las características intrínsecas de <intrin.h> en x86 (incluyendo x86-64).

    gcc para ARM utiliza un and r1, r1, #31 para la variable de conteo de gira, pero sigue el real girar con una sola instrucción: ror r0, r0, r1. Así que gcc no se da cuenta de que rotar-que cuenta son inherentemente modular. Como el BRAZO docs decir, «ROR con longitud de desplazamiento, n, más de 32 es el mismo como ROR con longitud de desplazamiento n-32«. Creo gcc se confunde aquí debido a la izquierda/a la derecha de turnos en el BRAZO saturar la cuenta, por lo que un cambio de 32 o más para borrar el registro. (A diferencia de x86, donde los cambios de la máscara de la cuenta el mismo que gira). Probablemente decide que necesita una instrucción Y antes de reconocer al girar lenguaje, debido a la forma no circular turnos de trabajo en dicho objetivo.

    Actual x86 compiladores todavía el uso de una instrucción adicional a la máscara de una variable de recuento de 8 y 16 bits gira, probablemente por la misma razón que no evite el Y en el BRAZO. Esto es una perdida de optimización, debido a que el rendimiento no depende de la rotación contar en cualquier x86-64 de la CPU. (El enmascaramiento de la cuenta se introdujo con 286 por razones de rendimiento debido a que se manejan turnos de forma iterativa, no con la constante de latencia como las Cpu modernas.)

    Por CIERTO, prefieren girar-derecha para la variable de conteo de gira, para evitar hacer que el compilador haga 32-n para aplicar a la izquierda girar sobre arquitecturas como ARM y MIPS que sólo proporcionan un girar a la derecha. (Esto optimiza la distancia con tiempo de compilación constante de cuenta.)

    Hecho de la diversión: BRAZO realmente no se han dedicado cambio/girar instrucciones, es sólo MOV con el operando origen pasando por el cañón de la palanca de cambios en ROR modo: mov r0, r0, ror r1. Así, un girar puede plegar en un registro-operando origen para una EOR instrucción o algo.


    Asegúrese de usar unsigned tipos de n y el valor de retorno, o de lo contrario no será una rotar. (gcc para x86 objetivos ¿aritmético a la derecha cambios, el cambio en las copias de la señal de bits en lugar de ceros, que conduce a un problema cuando OR los dos desplazado valores. Derecho-turnos de negativos enteros es la aplicación definida por el comportamiento en C.)

    También, asegúrese de que el cambio de cuenta es un entero de tipo, porque (-n)&31 con una firma tipo, podría ser un complemento o signo/magnitud, y no el mismo que el sistema modular de 2^n que se obtiene con unsigned o complemento a dos. (Ver comentarios en Regehr entrada en el blog). unsigned int hace bien en cada compilador que yo he mirado, para cada ancho de x. Algunos otros tipos de realidad de la derrota de los signos de reconocimiento para algunos compiladores, por lo que no sólo tiene que utilizar el mismo tipo de x.


    Algunos compiladores proporcionan las características intrínsecas de gira, que es mucho mejor que la de en línea-asm si la versión portátil no generar el código en el compilador de orientación. No hay cruz-plataforma de las características intrínsecas de cualquier compiladores, que yo sepa. Estos son algunos de los x86 opciones:

    • Documentos de Intel que <immintrin.h> proporciona _rotl y _rotl64 de las características intrínsecas, y lo mismo para el derecho de turno. MSVC requiere <intrin.h>, mientras gcc requiere <x86intrin.h>. Un #ifdef se ocupa de gcc frente de la cpi, pero el ruido no parece ofrecer ningún lugar, excepto en MSVC modo de compatibilidad con -fms-extensiones-fms-compatibilidad-fms-compatibilidad-version=17.00. Y la asm se emite para ellos chupa (extra de enmascarar y un CMOV).
    • MSVC: _rotr8 y _rotr16.
    • gcc e icc (no clang): <x86intrin.h> también proporciona __rolb/__rorb de 8 bits, girar a la izquierda/derecha, __rolw/__rorw (de 16 bits), __rold/__rord (32-bit), __rolq/__rorq (de 64 bits, sólo se define para 64 bits objetivos). Para reducir la gira, la aplicación utiliza __builtin_ia32_rolhi o ...qi, pero el de 32 y 64 bits gira se definen usando shift/o (sin protección contra la UB, ya que el código de ia32intrin.h sólo tiene que trabajar en el gcc para x86). De C de GNU, no parece haber ninguna cruz-plataforma de __builtin_rotate funciones de la manera que lo hace para __builtin_popcount (que se expande a lo óptimo en la plataforma de destino, incluso si no es una sola instrucción). La mayoría del tiempo usted consigue un buen código de idioma de reconocimiento.
    //For real use, probably use a rotate intrinsic for MSVC, or this idiom for other compilers.  This pattern of #ifdefs may be helpful
    #if defined(__x86_64__) || defined(__i386__)
    
    #ifdef _MSC_VER
    #include <intrin.h>
    #else
    #include <x86intrin.h>  //Not just <immintrin.h> for compilers other than icc
    #endif
    
    uint32_t rotl32_x86_intrinsic(rotwidth_t x, unsigned n) {
      //return __builtin_ia32_rorhi(x, 7);  //16-bit rotate, GNU C
      return _rotl(x, n);  //gcc, icc, msvc.  Intel-defined.
      //return __rold(x, n);  //gcc, icc.
      //can't find anything for clang
    }
    #endif

    Posiblemente algunos no-x86 compiladores tienen características intrínsecas, también, pero no vamos a ampliar esta comunidad-wiki respuesta a todos ellos. (Tal vez hacer que en la respuesta existente acerca de las características intrínsecas).


    (La versión antigua de esta respuesta sugiere MSVC específicos inline asm (que sólo funciona para 32 bits x86 código), o http://www.devx.com/tips/Tip/14043 para un C versión. Los comentarios están respondiendo a eso.)

    Inline asm derrotas muchas optimizaciones, especialmente MSVC estilo porque las fuerzas de los insumos para ser almacenado/reloaded. Una cuidadosamente escrito de C de GNU en línea-asm girar permitiría el recuento de ser un operando inmediato de tiempo de compilación constante cambio de cuenta, pero todavía no podía optimizar fuera por completo si el valor a ser desplazado es también una constante en tiempo de compilación después de inline. https://gcc.gnu.org/wiki/DontUseInlineAsm.

    • Curioso, ¿por qué no bits = CHAR_BIT * sizeof(n); y c &= bits - 1; y return ((n >> c) | (n << (bits - c))), que es lo que yo uso?
    • Su versión ha UB con bits=32, count=32, en el cambio por bits - c = 32 - 0. (No conseguí un ping de esto porque yo sólo editar el wiki, no escrito en el primer lugar.)
    • contar < bits es una constante exigencia de casi todas las CPUs y los lenguajes de programación de la aplicación de la rotación (a veces 0 ≤ count < bits, pero cambiando por la cantidad exacta de los bits es virtualmente siempre no se define o se redondea hacia abajo a una instrucción nop en lugar de despejar el valor, y la rotación, también.)
    • A la derecha, pero nuestro objetivo es escribir una función que alimenta el turno de contar directamente a una sola instrucción asm, sino que evita la UB en un nivel C para cualquier posible cambio de contar. Ya que C no tiene una rotar operador o función, queremos evitar la UB, en cualquiera de los componentes de este modismo. Preferiríamos que no se basan en el compilador el tratamiento de un C cambio de la misma manera como asm cambio de instrucciones sobre el destino de su compilación para. (Y por CIERTO, el BRAZO que hace cero el registro con la variable de conteo de turnos por más que el registro de ancho, tomando el recuento de la parte inferior de bytes del registro. Enlace en la respuesta.)
    • El común de los compiladores de trabajar bien con el idioma, si mal no recuerdo, pero se les permite hacer a los demonios de la mosca de la nariz si querían con un recuento de 0 la producción de x << 32. C realmente dice que es un comportamiento indefinido, no sólo una aplicación definida por el valor de resultado o algo.
    • hm seguro, pero simplemente no permitir que valor. (No importa, tengo a tu punto y tu respuesta, gracias por la información detallada explicación.)
    • Yo iba a decir «sólo uso portátil-fragmentos», pero luego he comprobado el código y parece (a) invocar la UB para cero cambio de cuenta y (b) sólo el uso de los elementos intrínsecos en MSVC. En general, a pesar de tener que como el compilable «código de referencia», por lo que funciona con todas las compilador y específicas de la plataforma hacks parece una buena idea…
    • La mejor versión de la plantilla de esto que he escrito se inicia con template <typename T, int width = sizeof T * CHAR_BIT>. Pero luego de no llegar a suponer que width es una potencia exacta de 2.
    • En el momento crítico de código es mejor utilizar las características intrínsecas, el corto precompilado versión del conocido funciones. Definitivamente no ralentizar el rendimiento global. Cuando implementación personalizada PUEDE reducir aún con la __forceinline modificator.
    • «suponiendo que uint32_t es exactamente 32 bits de ancho, a pesar de que C/C++ sólo se garantiza que es, al menos, que de ancho.» Donde has leído eso? Los typedefs son opcionales (no sé que) si no soportado por el hardware, sino que están garantizados para ser exactamente del tamaño: en.cppreference.com/w/c/types/integer

  2. 33

    Ya que es C++, el uso de una función en línea:

    template <typename INT> 
    INT rol(INT val) {
        return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
    }

    C++11 variante:

    template <typename INT> 
    constexpr INT rol(INT val) {
        static_assert(std::is_unsigned<INT>::value,
                      "Rotate Left only makes sense for unsigned types");
        return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
    }
    • Es esto realmente un girar a la izquierda? Y no es la parte con la sizeof falta un &, o algo?
    • Se parece a un girar a la derecha, pero por lo demás correcto
    • Fija la roation dirección, y esto supone que está pasando en ceros en ambos lados (que es la razón por la que no debería hacer esto por entero con signo de tipos).
    • no debería ser INT T?
    • Sí, por supuesto. Fijo.
    • Advertencia: Este código se rompe si INT es un entero con signo y el signo en que se encuentra! Prueba por ejemplo rol<std::int32_t>(1 << 31) que debe voltee a 1, pero en realidad se convierte en -1 (porque la señal se conserva).
    • Consulte ideone.com/aRait7 para un vivo ejemplo de este comportamiento y la propuesta de solución (fundición del tipo equivalente al tipo unsigned antes de cambiar).
    • Ya me lo comentó hace 5 años que no deberías usar firmado los tipos enteros. La rotación no tiene sentido en entero con signo de tipos de todos modos.
    • Lo siento por el ruido. Tal vez usted debe editar que en la respuesta en lugar de enterrar en los comentarios. (Me pregunto cómo se deslizó por mi aviso, pensé que me había leído todos los comentarios antes de escribir). De todos modos la función en sí no advertir acerca de los problemas e incluso un experimentado programador podría supervisar que él/ella está pasando un entero con signo. Al menos deberían ser un chequeo en tiempo de compilación que el pasado es de tipo entero sin signo.
    • Es probablemente vale la pena señalar que INT parece ser un tipo definido en MSVC++, por lo que el C++11 versión no funciona en windows a menos que el cambio que a otra cosa.
    • También, vs es la falta constexpr. Suspiro.
    • Usted puede utilizar std::numeric_limits<INT>::digits en lugar de CHAR_BIT * sizeof. Se me olvida si unsigned tipos no hayan utilizado el relleno (por ejemplo, 24 bits enteros almacenados en 32 bits), pero si es así, entonces digits sería mejor. Véase también gist.github.com/pabigot/7550454 para una versión con la comprobación de más de una variable de conteo de turno.
    • Son. Creo Cray hizo (utilizado registros de punto flotante con relleno donde exponente de campo sería).
    • por lo que el C++11 versión no funciona en windows, a menos que se cambie esto a algo más…’ Sí, cambiar a linux. 🙂

  3. 20

    La mayoría de los compiladores tienen características intrínsecas para que.
    Visual Studio por ejemplo _rotr8, _rotr16

    • wow! el camino más fácil, a continuación, la aceptación de la respuesta. por cierto, para un valor DWORD (32-bit) uso _rotr y _rotl.
  4. 16

    Definitivamente:

    template<class T>
    T ror(T x, unsigned int moves)
    {
      return (x >> moves) | (x << sizeof(T)*8 - moves);
    }
    • Es que 8 un error ortográfico de CHAR_BIT (que no necesita ser exactamente 8)?
    • Ya que esta es la misma respuesta que la mía (excepto el intercambio de derecha a izquierda), Pedro Cordes » comentar mi respuesta también se aplica aquí: uso std::numeric_limits<T>::digits.
  5. 7

    Cómo abt algo como esto, usando el estándar bitset …

    #include <bitset> 
    #include <iostream> 
    
    template <std::size_t N> 
    inline void 
    rotate(std::bitset<N>& b, unsigned m) 
    { 
       b = b << m | b >> (N-m); 
    } 
    
    int main() 
    { 
       std::bitset<8> b(15); 
       std::cout << b << '\n'; 
       rotate(b, 2); 
       std::cout << b << '\n'; 
    
       return 0;
    }

    HTH,

    • Necesidad de modificarlo para que se de cuenta de los cambios mayores que la longitud de la bitset.
    • Añadido m %= N; para dar cuenta de los cambios >= N.
  6. 6

    En los detalles se puede aplicar la siguiente lógica.

    Si el Patrón de Bits es 33602 en Entero

    1000 0011 0100 0010 
    

    y que necesita para Rodar con 2 derecho shifs a continuación:
    primero hacer una copia de un patrón de bits y, a continuación, mayús izquierda es: Longitud – RightShift
    es decir, la longitud es de 16 a la derecha cambio de valor es 2
    16 – 2 = 14

    Después de 14 veces a la izquierda cambio de obtener.

    1000 0000 0000 0000 
    

    Ahora derecho a cambiar el valor 33602, 2 veces como sea necesario.
    Usted obtener

    0010 0000 1101 0000 
    

    Ahora tomar una O entre 14 tiempo quedaron en el pasado el valor de y 2 veces desplazado a la derecha del valor.

    1000 0000 0000 0000 
    0010 0000 1101 0000 
    =================== 
    1010 0000 1101 0000 
    =================== 
    

    Y obtener su desplazado valor de conversión. Recuerde poco sabio operaciones son más rápidas y esto no requiere de ningún bucle.

    • Similar a las subrutinas de arriba… b = b << m | b >> (N-m);
    • No debería ser XOR, O no? 1 ^ 0 = 1, 0 ^ 0 = 0, etc. Si es O no es exclusivo, por lo que siempre va a ser 1.
  7. 5

    Si x es de 8 bits, puede utilizar este:

    x=(x>>1 | x<<7);
    • Probablemente se portan mal si x está firmado.
  8. 4

    Suponiendo que se desee desplazar a la derecha por L bits, y la entrada x es un número con N bits:

    unsigned ror(unsigned x, int L, int N) 
    {
        unsigned lsbs = x & ((1 << L) - 1);
        return (x >> L) | (lsbs << (N-L));
    }
  9. 3

    La respuesta correcta es la siguiente:

    #define BitsCount( val ) ( sizeof( val ) * CHAR_BIT )
    #define Shift( val, steps ) ( steps % BitsCount( val ) )
    #define ROL( val, steps ) ( ( val << Shift( val, steps ) ) | ( val >> ( BitsCount( val ) - Shift( val, steps ) ) ) )
    #define ROR( val, steps ) ( ( val >> Shift( val, steps ) ) | ( val << ( BitsCount( val ) - Shift( val, steps ) ) ) )
    • Probablemente se portan mal si val está firmado.
  10. 1

    C++20 std::rotl y std::rotr

    Ha llegado! http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html y debe agregarlo a la <bit> encabezado.

    cppreference dice que el uso va a ser como:

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

    dando salida:

    i          = 00011101
    rotl(i,0)  = 00011101
    rotl(i,1)  = 00111010
    rotl(i,4)  = 11010001
    rotl(i,9)  = 00111010
    rotl(i,-1) = 10001110

    Voy a darle una oportunidad cuando la ayuda llega a GCC GCC 9.1.0 con g++-9 -std=c++2a todavía no lo admite.

    La propuesta dice:

    Encabezado:

    namespace std {
      //25.5.5, rotating   
      template<class T>
        [[nodiscard]] constexpr T rotl(T x, int s) noexcept;
      template<class T>
        [[nodiscard]] constexpr T rotr(T x, int s) noexcept;

    y:

    25.5.5 de Rotación [bitops.rot]

    En las descripciones siguientes, vamos a N denotar std::numeric_limits<T>::digits.

    template<class T>
      [[nodiscard]] constexpr T rotl(T x, int s) noexcept;

    Restricciones: T es un entero de tipo entero (3.9.1 [basic.fundamentales]).

    Vamos a r s % N.

    Devuelve: Si r es 0, x; si r es positivo, (x << r) | (x >> (N - r)); si r es negativo, rotr(x, -r).

    template<class T>
      [[nodiscard]] constexpr T rotr(T x, int s) noexcept;

    Restricciones: T es un entero de tipo entero (3.9.1 [basic.fundamentales]).
    Vamos a r s % N.

    Devuelve: Si r es 0, x; si r es positivo, (x >> r) | (x << (N - r)); si r es negativo, rotl(x, -r).

    Un std::popcount también se ha añadido a contar el número de bits 1: Cómo contar el número de bits en un entero de 32 bits?

  11. 0

    Código Fuente
    x número de bits

    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;  
    }
  12. 0

    otra sugerencia

    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;
    }
  13. 0

    A continuación es una versión ligeramente mejorada de Dídac Pérez respuesta, con ambas direcciones a cabo, junto con una demostración de estas funciones «usos» de usar unsigned char y unsigned long long valores. Varias notas:

    1. Las funciones son insertados para las optimizaciones del compilador
    2. He utilizado un cout << +value truco para secamente producir un unsigned char numéricamente que he encontrado aquí: https://stackoverflow.com/a/28414758/1599699
    3. Recomiendo el uso de la explícita <put the type here> sintaxis para una mayor claridad y seguridad.
    4. He utilizado unsigned char para el shiftNum parámetro porque de lo que he encontrado en la sección Detalles Adicionales aquí:

    El resultado de un cambio de la operación no está definida si aditivo-expresión es
    negativo, o si aditivo-expresión es mayor que o igual a la
    número de bits en la (promovido) cambio de expresión.

    Este es el código que estoy usando:

    #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");
    }
  14. 0
    --- Substituting RLC in 8051 C for speed --- Rotate left carry
    Here is an example using RLC to update a serial 8 bit DAC msb first:
    (r=DACVAL, P1.4= SDO, P1.5= SCLK)
    MOV     A, r
    ?1:
    MOV     B, #8
    RLC     A
    MOV     P1.4, C
    CLR     P1.5
    SETB    P1.5
    DJNZ    B, ?1
    Here is the code in 8051 C at its fastest:
    sbit ACC_7  = ACC ^ 7 ; //define this at the top to access bit 7 of ACC
    ACC     =   r;
    B       =   8;  
    do  {
    P1_4    =   ACC_7;  //this assembles into mov c, acc.7  mov P1.4, c 
    ACC     <<= 1;
    P1_5    =   0;
    P1_5    =   1;
    B       --  ; 
    } while ( B!=0 );
    The keil compiler will use DJNZ when a loop is written this way.
    I am cheating here by using registers ACC and B in c code.
    If you cannot cheat then substitute with:
    P1_4    =   ( r & 128 ) ? 1 : 0 ;
    r     <<=   1;
    This only takes a few extra instructions.
    Also, changing B for a local var char n is the same.
    Keil does rotate ACC left by ADD A, ACC which is the same as multiply 2.
    It only takes one extra opcode i think.
    Keeping code entirely in C keeps things simpler sometimes.
  15. -1

    La sobrecarga de una función:

    unsigned int rotate_right(unsigned int x)
    {
    return (x>>1 | (x&1?0x80000000:0))
    }
    unsigned short rotate_right(unsigned short x) { /* etc. */ }
  16. -1
    #define ROTATE_RIGHT(x) ( (x>>1) | (x&1?0x8000:0) )
    • usted debe envolver x en los paréntesis para evitar sorpresas desagradables con expresiones como argumento para la macro.
    • Si el valor no es de 16 bits, en silencio obtener una tontería
    • Si definir como una macro, entonces uno también necesita tener cuidado para evitar el paso de una expresión con efectos secundarios como el argumento.

Dejar respuesta

Please enter your comment!
Please enter your name here