¿Alguien puede explicarme cómo funciona el intercambio XOR de dos variables sin variable temporal?
void xorSwap (int *x, int *y)
{
if (x != y) {
*x ^= *y;
*y ^= *x;
*x ^= *y;
}
}
Entiendo QUÉ hace, pero ¿alguien puede explicarme la lógica de cómo funciona?
language-agnostic
bit-manipulation
xor
mmcdole
fuente
fuente
Respuestas:
Puedes ver cómo funciona haciendo la sustitución:
Sustituyendo,
Debido a que xor es completamente asociativo y conmutativo:
Dado que
x xor x == 0
para cualquier x,Y dado que
x xor 0 == x
para cualquier x,Y el intercambio está hecho.
fuente
y2
ay1
. Me dispara que tienesx0
yx1
pero luego usasy0
yy2
. : -]Otras personas lo han explicado, ahora quiero explicar por qué fue una buena idea, pero ahora no lo es.
En el día en que teníamos CPU simples de ciclo único o ciclo múltiple, era más barato usar este truco para evitar costosas desreferencias de memoria o derramar registros en la pila. Sin embargo, ahora tenemos CPU con canalizaciones masivas. La tubería del P4 variaba desde tener 20 a 31 (más o menos) etapas en sus tuberías, donde cualquier dependencia entre la lectura y la escritura en un registro podría hacer que todo se detuviera. El intercambio de xor tiene algunas dependencias muy importantes entre A y B que en realidad no importan en absoluto, pero paralizan la tubería en la práctica. Una tubería detenida provoca una ruta de código lenta, y si este intercambio está en su bucle interno, se moverá muy lentamente.
En la práctica general, su compilador puede averiguar qué es lo que realmente quiere hacer cuando realiza un intercambio con una variable temporal y puede compilarlo en una sola instrucción XCHG. El uso de xor swap hace que sea mucho más difícil para el compilador adivinar su intención y, por lo tanto, es mucho menos probable que la optimice correctamente. Sin mencionar el mantenimiento del código, etc.
fuente
Me gusta pensar en ello gráficamente en lugar de numéricamente.
Digamos que comienzas con x = 11 e y = 5 En binario (y voy a usar una máquina hipotética de 4 bits), aquí tienes xey
Ahora para mí, XOR es una operación de inversión y hacerlo dos veces es un espejo:
fuente
Aquí hay uno que debería ser un poco más fácil de asimilar:
Ahora, uno puede entender el truco de XOR un poco más fácilmente si comprende que ^ se puede pensar en + o - . Tal como:
, entonces:
fuente
La mayoría de las personas intercambiarían dos variables xey usando una variable temporal, como esta:
Aquí hay un buen truco de programación para intercambiar dos valores sin necesidad de una temperatura:
Más detalles en Intercambiar dos variables usando XOR
fuente
La razón por la que funciona es porque XOR no pierde información. Podría hacer lo mismo con la suma y la resta ordinarias si pudiera ignorar el desbordamiento. Por ejemplo, si el par de variables A, B contiene originalmente los valores 1,2, podría intercambiarlos así:
Por cierto, hay un viejo truco para codificar una lista enlazada bidireccional en un solo "puntero". Suponga que tiene una lista de bloques de memoria en las direcciones A, B y C. La primera palabra en cada bloque es, respectivamente:
Si tiene acceso al bloque A, le da la dirección de B. Para llegar a C, toma el "puntero" en B y resta A, y así sucesivamente. Funciona igual de bien al revés. Para recorrer la lista, debe mantener los punteros en dos bloques consecutivos. Por supuesto, usaría XOR en lugar de suma / resta, por lo que no tendría que preocuparse por el desbordamiento.
Puede extender esto a una "web vinculada" si quiere divertirse.
fuente
int
desbordamiento es UB)@VonC tiene razón, es un buen truco matemático. Imagínese palabras de 4 bits y vea si esto ayuda.
fuente
Básicamente, hay 3 pasos en el enfoque XOR:
a '= a XOR b (1)
b' = a 'XOR b (2)
a ”= a' XOR b '(3)
Para entender por qué esto funciona, primero tenga en cuenta que:
Después del Paso (1), la representación binaria de a tendrá 1 bits solo en las posiciones de bit donde a y b tienen bits opuestos. Es decir (ak = 1, bk = 0) o (ak = 0, bk = 1). Ahora, cuando hacemos la sustitución en el paso (2) obtenemos:
b '= (a XOR b) XOR b
= a XOR (b XOR b) porque XOR es asociativo
= a XOR 0 debido a [4] arriba
= a debido a la definición de XOR (ver 1 arriba)
Ahora podemos sustituir en el Paso (3):
a ”= (a XOR b) XOR a
= (b XOR a) XOR a porque XOR es conmutativo
= b XOR (a XOR a) porque XOR es asociativo
= b XOR 0 debido a [4] arriba
= b debido a la definición de XOR (ver 1 arriba)
Información más detallada aquí: Necesario y suficiente
fuente
Como nota al margen, reinventé esta rueda de forma independiente hace varios años en forma de intercambio de enteros haciendo:
(Esto se menciona anteriormente de una manera difícil de leer),
El mismo razonamiento se aplica exactamente a los intercambios xor: a ^ b ^ b = a y a ^ b ^ a = a. Dado que xor es conmutativo, x ^ x = 0 y x ^ 0 = x, esto es bastante fácil de ver ya que
y
Espero que esto ayude. Esta explicación ya se ha dado ... pero no muy claramente en mi opinión.
fuente
Solo quiero agregar una explicación matemática para que la respuesta sea más completa. En teoría de grupos , XOR es un grupo abeliano , también llamado grupo conmutativo. Significa que cumple cinco requisitos: cierre, asociatividad, elemento de identidad, elemento inverso, conmutatividad.
Fórmula de intercambio XOR:
Expande la fórmula, sustituye a, b con la fórmula anterior:
Conmutatividad significa "a XOR b" igual a "b XOR a":
Asociatividad significa "(a XOR b) XOR c" igual a "a XOR (b XOR c)":
El elemento inverso en XOR es él mismo, significa que cualquier valor XOR consigo mismo da cero:
El elemento de identidad en XOR es cero, significa que cualquier valor XOR con cero se deja sin cambios:
Y puede obtener más información en teoría de grupos .
fuente
Otros han publicado explicaciones, pero creo que se entendería mejor si se acompaña de un buen ejemplo.
Tabla de verdad de XOR
Si consideramos la tabla de verdad anterior y tomamos los valores
A = 1100
yB = 0101
podemos intercambiar los valores como tales:fuente