GAP, 368 Bytes
Para os matemáticos, isso é multiplicação no anel polinomial F_2 [x], identificando polinômios com números naturais, avaliando x = 2 como um polinômio sobre Z.
Claro, vamos fazer isso! (isso é apenas pouco jogado, o objetivo era passar para F 2 [x] e fazer os cálculos mais do que qualquer tentativa de ser uma entrada vencedora)
Aqui está o 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;
Aqui está o código não destruído com explicação:
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;
Ok, então, primeiro, criamos o anel polinomial univariado sobre o campo F 2 e o chamamos R
. Observe que GF(2)
é F 2 no GAP.
R:=PolynomialRing(GF(2));
Em seguida, vamos atribuir a variável GAP x
ao indeterminado do anel R
. Agora, sempre que eu disser x
no GAP, o sistema saberá que estou falando sobre o indeterminado do anel R
.
x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];
Next, we have two functions, which are inverse maps of each other. These maps are both onto, but they are not structure preserving, so I couldn't figure out a better way to implement them in GAP. There almost certainly is a better way, if you know it, please comment!
O primeiro mapa, to_ring
pega um número inteiro e mapeia para o seu elemento de anel correspondente. Isso é feito usando um algoritmo de conversão em binário, onde todo o 1
que apareceria em binário é substituído por um x^n
onde n
é a potência apropriada que 2 seria necessária se o número fosse realmente binário.
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;
A próxima função reverte isso. to_ints
pega um elemento de anel e mapeia para seu número inteiro correspondente. Faço isso obtendo uma lista dos coeficientes do polinômio e, para cada coeficiente diferente de zero, o resultado é aumentado em 2 ^ n, da mesma forma que converteríamos binário em 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 a etapa final, chamamos essas funções. Pegamos as duas entradas inteiras, as convertemos em elementos no anel R
, depois multiplicamos esses elementos e enviamos o produto de volta aos números inteiros.
return to_ints( to_ring(i)*to_ring(j));
PCLMULQDQ
da extensão CLMUL. Infelizmente, obtive voto negativo pelo meu conhecimento das instruções x86 definidas anteriormente (relacionadas aPEXT/PDEP
), então vou deixar isso como um comentário aqui.