Algoritmo de intercambio XOR![]() Na programación por computador, o intercambio por OR exclusivo (en inglés XOR swap) é un algoritmo que emprega a disxunción exclusiva bit a bit para intercambiar os valores de dúas variábeis. A diferenza do método xeralmente empregado, evita o uso dunha variable temporal para facer o intercambio. O algoritmo é, principalmente, un xeito de demostrar algunhas propiedades do OR exclusivo. Tense falado do seu uso como unha optimización para os programas, mais practicamente non existe ningún caso onde o intercambio por OR exclusivo proporcione algún beneficio sobre o estándar. O algoritmoO intercambio convencional de variábeis require o uso dunha variábel temporal de almacenamento. Con todo, usando o algoritmo de intercambio por OR exclusivo, non se precisa ningún tipo de almacenamento temporal. O algoritmo execútase do seguinte xeito:[1][2] X := Y XOR X; // Faise un XOR de X e Y e gárdase o resultado en X
Y := X XOR Y; // Faise un XOR do novo X e de Y e gárdase o resultado en Y
X := Y XOR X; // Faise un XOR dos novos X e Y e gárdase o resultado en X
Como XOR é unha operación conmutativa, X XOR Y e Y XOR X poden usarse indistintamente en calquera das tres liñas. Débese ter en conta que nalgunhas arquitecturas o primeiro operando da instrución XOR especifica a localización na que o resultado da operación será almacenado, facendo que non se poidan intercambiar. En xeral o algoritmo correspóndese a tres instrucións máquina, representadas polo seguinte pseudocódigo e instrucións ensamblador na táboa:
No exemplo de arriba, no código do ensamblador System/370, R1 e R2 son rexistros distintos, e cada operación Con todo, no pseudocódigo (ou implementación nunha linguaxe de alto nivel), o algoritmo falla se x e y utilizan a mesma dirección, xa que o valor almacenado naquela dirección será posto a cero pola primeira instrución XOR, e quedará a cero; non será "intercambiada consigo mesmo". Isto non é o mesmo ca ter os mesmos valores en x e y. O problema só xorde cando x e y usan a mesma dirección de almacenamento, caso no que os seus valores xa teñen que ser iguais. Isto é, se x e y usan a mesma dirección de almacenamento, entón a liña: X := X XOR Y
porá x a cero (pois x = y e entón X XOR Y é cero) e porá y a cero (xa que almacénanse na mesma dirección), facendo que x e y perdan os seus valores orixinais. Proba de correcciónUnha operación binaria XOR sobre cadeas de bits de lonxitude mostra as seguintes propiedades (onde denota XOR):
Supoña que temos dous rexistros distintos
Interpretación na álxebra linealComo a operación XOR pode ser interpretada como unha suma binaria e un par de bits poden ser interpretados como un vector nun espazo vectorial bidimensional sobre o campo de dous elementos, os pasos no algoritmo pódense interpretar como multiplicacións por matrices 2×2 sobre o campo con dous elementos. Para simplificar, supoña inicialmente que x e y son un bit cada un, non vectores de bits. Por exemplo, o paso: X := X XOR Y
que tamén ten implícito: Y := Y
corresponde á matriz como A secuencia de operacións é entón expresado como: (traballando con valores binarios, así ), o cal expresa a matriz elemental de cambiar dúas filas (ou columnas) en termos das transveccións (en inglés shears) de engadir un elemento ao outro. Para xeneralizar a onde X e Y non son bits, se non vectors de lonxitude n, estas matrices 2×2 son substituídas por matrices de bloque 2nx2n como Estas matrices están operando valores, non variábeis (con direccións de almacenamento), por iso esta interpretación abstráese de problemas con direccións de almacenamento e do problema de ter ambas variábeis na mesma dirección. Exemplo de códigoUnha función de C que aplica o algoritmo de intercambio XOR: void xor_swap(int *x, int *y)
{
if (x == y) return;
*x ^= *y;
*y ^= *x;
*x ^= *y;
}
O código primeiro comproba se os enderezos das variábeis son distintos e utiliza unha cláusula de garda para saír da función se son iguais. Se non se controlara, en caso de ser iguais, o algoritmo executaría un triplo #define XORSWAP_UNSAFE(a, b) \
((a) ^= (b), (b) ^= (a), \
(a) ^= (b)) /* Non funciona cando a e b son o mesmo obxecto - asigna cero \
(0) ao obxecto nese caso */
#define XORSWAP(a, b) \
((&(a) == &(b)) ? (a) /* Comproba que as direccións sexan distintas */ \
: XORSWAP_UNSAFE(a, b))
Razóns para evitalo na prácticaEn arquitecturas de computadoras modernas, a técnica de XOR pode ser máis lenta ca utilizar unha variábel temporal para facer o intercambio. Polo menos nas CPUs x86 recentes, tanto en AMD coma en Intel, moverse entre rexistros regularmente xera cero latencia (isto é chamado eliminación MOV). Incluso se non hai ningún rexistro estructural dispoñible, a instrución AliasingO intercambio XOR tamén é complicado na práctica polo aliasing. Se se intenta facer un intercambio XOR dos contidos dunha dirección consigo mesmo, o resultado é que a dirección é posta a cero e o seu valor pérdese. Por tanto, o intercambio XOR non debe ser empregado ás cegas nunha linguaxe de alto nivel se o aliasing é posíbel. Este problema non aplica se a técnica é utilizada en ensamblador para intercambiar os contidos de dous rexistros.
Ocorren problemas similares coa chamada por nome, coma no Dispositivo de Jensen, onde intercambiar temp = i;
i = A[i];
A[i] = temp;
muda o valor de i na segunda liña, o que resulta no valor incorrecto VariaciónsO principio subxacente do algoritmo de intercambio por XOR pode ser aplicado a calquera operación que cumpla cos criterios L1 a L4 xa mencionados. Substituíndo XOR pola suma e a resta obtemos varias formulacións lixeiramente diferentes, mais en gran parte equivalentes. Por exemplo:[4] void add_swap(unsigned int* x, unsigned int* y)
{
*x = *x + *y;
*y = *x - *y;
*x = *x - *y;
}
Ao contrario que co intercambio XOR, esta variación require que o procesador subxacente ou que a linguaxe de programación empregue un método como a aritmética modular ou a precisión arbitraria para garantir que o cómputo de Con todo, a implementación de Isto non se cumpre ao traballar co tipo A secuencia de operacións en Notas
|