¿Cuál es el equivalente de C# (.NET 2.0) de _rotl
y _rotr
de C++?C# girar en sentido horario a la izquierda y girar a la derecha
Respuesta
Es esto lo que estamos tratando de hacer?
Jon Skeet answered this in another site
Básicamente lo que quiere es
(por la izquierda)
(original << bits) | (original >> (32 -bits))
o
(por la derecha)
(original >> bits) | (original << (32 -bits))
Al así que, como Mehrdad ya ha sugerido, esto solo funciona para uint, que es el ejemplo que Jon da también.
no hay ninguna característica integrada de idioma para rotación de la broca en C#, pero estos métodos de extensión deben hacer el trabajo:
public static uint RotateLeft(this uint value, int count)
{
return (value << count) | (value >> (32 - count))
}
public static uint RotateRight(this uint value, int count)
{
return (value >> count) | (value << (32 - count))
}
Nota: Como Mehrdad señala, desplazamiento a la derecha (>>
) para firmar enteros es una peculiaridad: llena los MSB con el bit de signo en lugar de 0, como lo hace con los números sin signo. Ahora he cambiado los métodos para tomar y devolver uint
(entero sin signo de 32 bits) en su lugar, esto también está en mayor acuerdo con las funciones C++ rotl
y rotr
. Si quieres rotar números enteros, solo defiéndelos antes de pasar, y vuelve a emitir el valor de retorno, por supuesto.
Ejemplo de uso:
int foo1 = 8.RotateRight(3); // foo1 = 1
int foo2 = int.MinValue.RotateLeft(3); // foo2 = 4
(. Tenga en cuenta que es int.MinValue
111111111111111111111111 - 32 1s en binario)
La versión ingenua de desplazamiento no funcionará. La razón es, justo cambiantes números con signo se llenan los bits de la izquierda con el bit señal, no 0:
Puede comprobar este hecho con:
Console.WriteLine(-1 >> 1);
La forma correcta es:
public static int RotateLeft(this int value, int count)
{
uint val = (uint)value;
return (int)((val << count) | (val >> (32 - count)));
}
public static int RotateRight(this int value, int count)
{
uint val = (uint)value;
return (int)((value >> count) | (value << (32 - count)));
}
o puede cambiar el método de extensión para traer un uint y devolver un uint, que es lo que hizo Jon – Joseph
@Joseph: En ese caso, debe hacer el molde manualmente cuando llame con un int. –
Sí, tendría más sentido para la función solo tomar/devolver uint (eso es lo que hice en mi publicación actualizada también). De lo contrario, si realmente quieres rotar una uint, estarías lanzando 4 veces cuando de hecho no necesitas hacer nada. – Noldorin
Tenga en cuenta que si desea crear sobrecargas que operen con valores integrales más cortos, debe agregar un paso adicional, como se muestra en:
public static byte RotateLeft(
this byte value,
int count)
{
// Unlike the RotateLeft(uint, int) and RotateLeft(ulong, int)
// overloads, we need to mask out the required bits of count
// manually, as the shift operaters will promote a byte to uint,
// and will not mask out the correct number of count bits.
count &= 0x07;
return (byte)((value << count) | (value >> (8 - count)));
}
La operación de enmascaramiento no es necesaria para las sobrecargas de 32 bits y de 64 bits, ya que los operadores del cambio se encargan de ellos para los tamaños de operandos de la izquierda.
// if you are using string
string str=Convert.ToString(number,2);
str=str.PadLeft(32,'0');
//Rotate right
str = str.PadLeft(33, str[str.Length - 1]);
str= str.Remove(str.Length - 1);
number=Convert.ToInt32(str,2);
//Rotate left
str = str.PadRight(33, str[0]);
str= str.Remove(0,1);
number=Convert.ToInt32(str,2);
¡Eso es ** muy ** ineficiente! –
Con la última C# 7, ahora puede crear métodos de extensión por-árbitro, por lo que puede deshacerse de la busywork de almacenar permanentemente el valor de retorno de la función auxiliar de nuevo en el variable.
Esto optimiza las funciones de rotación, y elimina una clase común de error donde se olvida volver a almacenar el valor de retorno de la función, pero posiblemente introduciendo un nuevo tipo de error completamente diferente - donde ValueTypes
se modifican inadvertidamente in-situ cuando no quería o esperaba que lo fueran.
public static void Rol(ref this ulong ul) => ul = (ul << 1) | (ul >> 63);
public static void Rol(ref this ulong ul, int N) => ul = (ul << N) | (ul >> (64 - N));
public static void Ror(ref this ulong ul) => ul = (ul << 63) | (ul >> 1);
public static void Ror(ref this ulong ul, int N) => ul = (ul << (64 - N)) | (ul >> N);
/// note: ---^ ^---^--- extension method can now use 'ref' for ByRef semantics
lo general, me gustaría estar seguro de poner en [MethodImpl(MethodImplOptions.AggressiveInlining)]
pequeños métodos como estos, pero después de algunas investigaciones (sobre 64) descubrí que no es necesario en absoluto aquí. Si el JIT determina que el método es elegible (por ejemplo, si desmarca la casilla de verificación del depurador VisualStudio 'Suppress JIT Optimization', que está habilitada de manera predeterminada), los métodos se marcarán independientemente, y ese es el caso aquí.
para demostrar el uso de un por-ref método extensión, me centraré sólo en el primer método se muestra más arriba "Rotar a la izquierda", y comparar la salida JIT entre lo tradicional por valor método de extensión y el más reciente por-ref enfoque. Aquí están los dos métodos de prueba para ser comparados en x64Release en .NET 4.7 en Windows 10. Como se mencionó anteriormente, esto será con la optimización JIT 'no suprimida', por lo que bajo estas condiciones de prueba como ' Verá, las funciones desaparecerán por completo en el código en línea.
static ulong Rol_ByVal(this ulong ul) => (ul << 1) | (ul >> 63);
static void Rol_ByRef(ref this ulong ul) => ul = (ul << 1) | (ul >> 63);
// notice reassignment here ---^ (c̲a̲l̲l̲e̲e̲ doing it instead of caller)
Y aquí está el código C# para cada sitio de llamada correspondiente. Dado que el código AMD64 totalmente optimizado para JIT es tan pequeño, también puedo incluirlo aquí. Este es el caso óptimo:
static ulong x = 1; // static so it won't be optimized away in this simple test
// ------- ByVal extension method; c̲a̲l̲l̲e̲r̲ must reassign 'x' with the result -------
x = x.Rol_ByVal();
// 00007FF969CC0481 mov eax,dword ptr [7FF969BA4888h]
// 00007FF969CC0487 rol rax,1
// 00007FF969CC048A mov qword ptr [7FF969BA4888h],rax
// ------- New in C#7, ByRef extension method can directly alter 'x' in-situ -------
x.Rol_ByRef();
// 00007FF969CC0491 rol qword ptr [7FF969BA4888h],1
Wow. Sí, eso no es broma. De buenas a primeras, podemos ver que la flagrante falta de un OpCodes.Rot
-family de instrucciones del ECMA CIL (NET) lenguaje intermedio es un problema no total de; El jitter fue capaz de ver a través de nuestro montón de código de solución C# para adivinar su intención simple y pura, y el x64 JIT lo implementa con gran código. Sorprendentemente, la versión ByRef usa una sola instrucción para realizar la rotación directamente en la dirección de destino de la memoria principal sin siquiera cargarla en un registro.
Todavía puede ver un rastro residual del exceso de copia que era necesario en el caso de by-val. Aquí hay solo 8 bytes de barajado, lo que no será un gran problema, pero recuerde que el ValueType
podría fácilmente tener varios miles de bytes. Obviamente, pasar a los que tienen valor por debajo todo el tiempo probablemente indicaría un defecto de diseño fundamental, pero el punto aquí es que solo cuatro simples líneas de código nativo muestran claramente no solo el potencial de desastre, sino también la solución.
Para seguir investigando, tenemos que volver a suprimir las optimizaciones de JIT en la sesión de depuración. Hacerlo hará que nuestros métodos de extensión auxiliar vuelvan, con cuerpos completos y marcos de pila. Estas versiones clunkier exagerarán aún más (y exacerbarán) el problema mostrado de manera tan minimalista arriba. Primero, veamos los sitios de llamadas.Aquí realmente empezar a ver el efecto de los tradicionales ValueType
la semántica, es decir, las longitudes que se requieren para asegurar que de cada marco de pila no se puede manipular a sus padres ValueType
copias:
por valor:
x = x.Rol_ByVal();
// 00007FF969CE049C mov rcx,qword ptr [7FF969BC4888h]
// 00007FF969CE04A3 call 00007FF969CE00A8
// 00007FF969CE04A8 mov qword ptr [rbp-8],rax
// 00007FF969CE04AC mov rcx,qword ptr [rbp-8]
// 00007FF969CE04B0 mov qword ptr [7FF969BC4888h],rcx
por referencia
x.Rol_ByRef();
// 00007FF969CE04B7 mov rcx,7FF969BC4888h
// 00007FF969CE04C1 call 00007FF969CE00B0
// ...all done, nothing to do here; the callee did everything in-place for us
Como era de esperar de un código C# asociado con cada uno de estos dos fragmentos, vemos que el por-val persona que llama tiene un montón de trabajo que hacer después de que vuelva la llamada. Este es el proceso de sobrescribir la copia principal del valor ulong
'x' con el valor completamente independiente ulong
que se devuelve en el registro rax
.
Por último, pero no menos importante, es instructivo mirar el código nativo que emite x64 Release JIT para las funciones Rol_ByVal
y Rol_ByRef
. Como se señaló, esto requiere obligar al JIT a "suprimir" las optimizaciones que normalmente aplicaría durante su conversión de una vez por aplicación (llamada "just-in-time") de nuestras instrucciones .NET IL en speedy código nativo, ajustado para la plataforma detectada.
Para centrarme en la pequeña pero crucial diferencia entre los dos, he eliminado algunos de los repetidores administrativos. (Dejé la configuración y el desglose del marco de pila para el contexto, y para mostrar cómo en este ejemplo, las cosas auxiliares eclipsan las instrucciones reales). ¿Puedes ver la indirección del ByRef en acción? Bueno, ayuda que me indicó que: -/
static ulong Rol_ByVal(this ulong ul) => (ul << 1) | (ul >> 63);
// 00007FF969CD0760 push rbp
// 00007FF969CD0761 sub rsp,20h
// 00007FF969CD0765 lea rbp,[rsp+20h]
// ...
// 00007FF969CE0E4C mov rax,qword ptr [rbp+10h]
// 00007FF969CE0E50 rol rax,1
// 00007FF969CD0798 lea rsp,[rbp]
// 00007FF969CD079C pop rbp
// 00007FF969CD079D ret
static void Rol_ByRef(ref this ulong ul) => ul = (ul << 1) | (ul >> 63);
// 00007FF969CD0760 push rbp
// 00007FF969CD0761 sub rsp,20h
// 00007FF969CD0765 lea rbp,[rsp+20h]
// ...
// 00007FF969CE0E8C mov rax,qword ptr [rbp+10h]
// 00007FF969CE0E90 rol qword ptr [rax],1 <--- !
// 00007FF969CD0798 lea rsp,[rbp]
// 00007FF969CD079C pop rbp
// 00007FF969CD079D ret
Usted puede notar que ambas llamadas son, de hecho, pasando ejemplo de los padres del valor ulong
por referencia - ambos ejemplos son idénticos en este sentido. El padre indica la dirección donde reside su copia privada de ul
en el marco de la pila superior. Resulta que no es necesario aislar las calles de leyendo aquellas instancias en las que se encuentran, siempre que podamos estar seguros de que nunca escriben en esos punteros. Este es un enfoque "diferido" o diferido que asigna a cada marco de pila inferior (hijo) la responsabilidad de preservar ValueType semántica de sus llamadas más altas. No es necesario que una persona que llama copie de forma proactiva cualquier ValueType
que se transmita a un marco secundario si el niño nunca termina sobrescribiéndolo; Para maximizar la evitación de copias innecesarias tanto como sea posible, solo el niño puede tomar la determinación más reciente posible.
También es interesante que podríamos tener una explicación aquí para el uso torpe de rax
en el primer ejemplo 'ByVal' que mostré. Después de que el método de valor por defecto se había reducido por completo mediante la creación de líneas, ¿por qué la rotación todavía tenía que pasar en un registro?
Bien, en estas últimas dos versiones de cuerpo completo está claro que el primer método devuelve ulong
y el segundo es void
.Dado que se pasa un valor de retorno en rax
, el método ByVal aquí tiene que buscarlo en ese registro de todos modos, por lo que es obvio que también debe rotarlo. Debido a que el método ByRef no necesita devolver ningún valor, no necesita pegar nada para su llamador en ninguna parte, y mucho menos en rax
. Parece probable que "no tener que preocuparse por rax
" libera el código ByRef para apuntar a la instancia ulong
que su padre ha compartido 'where lies', usando el elegante qword ptr
para indirecto en la memoria del marco de pila padre, en lugar de usar un registro. Esa es mi explicación especulativa, pero quizás creíble, para el misterio "residual rax
" que vimos anteriormente.
- 1. Girar imagen en android
- 2. Flotante a la izquierda y a la derecha
- 3. Girar imagen matemáticas (C#)
- 4. Girar la imagen correspondiente a la función de arrastre táctil en iPhone
- 5. Girar cara en la imagen
- 6. ¿Girar una cadena en C++?
- 7. MeasureString() almohadilla el texto a la izquierda y la derecha
- 8. C/C++ Bit haciendo girar
- 9. Desbordamiento a la izquierda en lugar de a la derecha
- 10. C++/OpenGL - Girar un rectángulo
- 11. De derecha a izquierda UILabels
- 12. Girar una imagen en C/C++
- 13. ¿Calcula la forma más corta de rotar, derecha o izquierda?
- 14. Girar imagen en UIImageView
- 15. Iphone y texto de derecha a izquierda
- 16. Texto alineado a la izquierda, centro y a la derecha en la misma línea
- 17. forma única para girar la deg fondo 180, (no girar la fuente)
- 18. Animación de bloques UIView mover vista de izquierda a derecha y volver a la izquierda
- 19. ¿Cómo enviar texto a la impresora con la dirección de derecha a izquierda en C#
- 20. Girar una UITableViewCell personalizada
- 21. ¿Girar imágenes alrededor de un círculo?
- 22. Girar UIView iPhone
- 23. Girar un Swing JLabel
- 24. Girar un vector (matriz)
- 25. Android Animate Girar
- 26. texto: derecha a izquierda (CSS)
- 27. Girar modelo 3D en XNA
- 28. H1 a la izquierda, "botones" de la derecha, alineado verticalmente
- 29. ¿Por qué StackPanel no colocará textblock a la izquierda y botón a la derecha en Silverlight?
- 30. Cómo alinear a la derecha y alinear cadenas de texto a la izquierda en Bash
Esto funciona correctamente ** solo ** si 'original' es' uint'. Tenga en cuenta que Jon Skeet lo hace con 'uint'. –
@Merhdad Gracias Actualicé la respuesta para reflejar. – Joseph
@Mehrdad Afortunadamente estaba buscando una solución con 'uint' – Prithis