GAP , 368 bytes
Para los matemáticos, esto es multiplicación en el anillo polinomial F_2 [x], identificando polinomios con números naturales mediante la evaluación de x = 2 como un polinomio sobre Z.
Claro, hagámoslo! (esto no se juega con precisión, lo importante era pasar a F 2 [x] y hacer los cálculos más que cualquier intento de ser una entrada ganadora)
Aquí está el código
f:=function(i,j)R:=PolynomialRing(GF(2));x:=IndeterminatesOfPolynomialRing(R);x:=x[1];a:=function(i)local n,r;r:=0*x;while not i=0 do n:=0;while 2^n<=i do n:=n+1;od;n:=n-1;r:=r+x^n;i:=i-2^n;od;return r;end;b:=function(r)local c,i,n;i:=0;n:=0;for c in CoefficientsOfUnivariatePolynomial(r) do if c=Z(2)^0 then n:=n+2^i;fi;i:=i+1;od;return n;end;return b(a(i)*a(j));end;
Aquí está el código no codificado con explicación:
xor_multiplication:=function(i,j)
R:=PolynomialRing(GF(2));
x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];
to_ring:=function(i)
local n,r;
r:=0*x;
while not i=0 do
n:=0;
while 2^n<=i do
n:=n+1;
od;
n:=n-1;
r:=r+x^n;
i:=i-2^n;
od;
return r;
end;
to_ints:=function(r)
local c,i,n;
i:=0;n:=0;
for c in CoefficientsOfUnivariatePolynomial(r) do
if c=Z(2)^0 then
n:=n+2^i;
fi;
i:=i+1;
od;
return n;
end;
return to_ints( to_ring(i)*to_ring(j));
end;
Bien, primero, creamos el anillo polinómico univariante sobre el campo F 2 y lo llamamos R
. Tenga en cuenta que GF(2)
es F 2 en GAP.
R:=PolynomialRing(GF(2));
A continuación, vamos a asignar la variable GAP x
a lo indeterminado del anillo R
. Ahora, cada vez que digo x
en GAP, el sistema sabrá que estoy hablando de lo indeterminado del anillo R
.
x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];
A continuación, tenemos dos funciones, que son mapas inversos entre sí. Estos mapas están en ambos, pero no conservan la estructura, por lo que no pude encontrar una mejor manera de implementarlos en GAP. Es casi seguro que hay una mejor manera, si lo sabes, ¡por favor comenta!
El primer mapa, to_ring
toma un número entero y lo asigna a su elemento de anillo correspondiente. Lo hace mediante el uso de una conversión a algoritmo binario, donde cada1
que aparezca en binario se reemplaza por un x^n
dónde n
es la potencia adecuada que tomaría 2 si el número fuera realmente binario.
to_ring:=function(i)
local n,r;
r:=0*x; # initiate r to the zero element of R
while not i=0 do # this is a modified binary algorithm
n:=0;
while 2^n<=i do
n:=n+1;
od;
n:=n-1;
r:=r+x^n;
i:=i-2^n;
od;
return r;
end;
La siguiente función invierte esto. to_ints
toma un elemento de anillo y lo asigna a su número entero correspondiente. Hago esto obteniendo una lista de los coeficientes del polinomio y para cada coeficiente distinto de cero, el resultado aumenta en 2 ^ n, de la misma manera que convertiríamos binario a decimal.
to_ints:=function(r)
local c,i,n;
i:=0;n:=0;
for c in CoefficientsOfUnivariatePolynomial(r) do
if c=Z(2)^0 then
# ^-- Right here you'll notice that the Z(2) is basically '1' in GF(2). So Z(2)^0 ~ 1 and Z(2)*0 ~ 0
# effectively, this line checks for nonzero coefficients
n:=n+2^i;
fi;
i:=i+1;
od;
return n;
end;
Para el paso final, llamamos a estas funciones. Tomamos las dos entradas enteras, las convertimos en elementos en el anillo R
, luego multiplicamos estos elementos y enviamos el producto a los enteros.
return to_ints( to_ring(i)*to_ring(j));
PCLMULQDQ
de la extensión CLMUL. Desafortunadamente, me votaron negativamente por mi conocimiento del conjunto de instrucciones x86 antes (relacionado conPEXT/PDEP
), así que voy a dejar esto como un comentario aquí.