GAP , 368 byte
Per i matematici, questa è la moltiplicazione nell'anello polinomiale F_2 [x], identificando i polinomi con numeri naturali valutando a x = 2 come un polinomio su Z.
Certo, facciamolo! (questo è solo vagamente giocato a golf, il punto era più di spostarsi in F 2 [x] e fare i calcoli più di qualsiasi tentativo di essere una voce vincente)
Ecco il codice
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;
Ecco il codice non golfato con spiegazione:
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, quindi prima di tutto, creiamo l'anello polinomiale univariato sul campo F 2 e lo chiamiamo R
. Si noti che GF(2)
è F 2 in GAP.
R:=PolynomialRing(GF(2));
Successivamente, assegneremo la variabile GAP x
all'indeterminato dell'anello R
. Ora, ogni volta che dico x
in GAP, il sistema saprà che sto parlando dell'indeterminato dell'anello R
.
x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];
Successivamente, abbiamo due funzioni, che sono mappe inverse l'una dell'altra. Queste mappe sono entrambe su, ma non preservano la struttura, quindi non sono riuscito a trovare un modo migliore per implementarle in GAP. C'è quasi sicuramente un modo migliore, se lo conosci, per favore commenta!
La prima mappa, to_ring
prende un numero intero e lo mappa al suo elemento ad anello corrispondente. Lo fa usando una conversione in algoritmo binario, dove ogni cosa 1
che appare in binario viene sostituita da una x^n
dove n
è la potenza appropriata che 2 prenderebbe se il numero fosse effettivamente 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 prossima funzione inverte questo. to_ints
prende un elemento ring e lo mappa al suo intero corrispondente. Lo faccio ottenendo un elenco dei coefficienti del polinomio e per ogni coefficiente diverso da zero, il risultato viene aumentato di 2 ^ n, nello stesso modo in cui convertiremmo binario in decimale.
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;
Per il passaggio finale, chiamiamo queste funzioni. Prendiamo i due input interi, li convertiamo in elementi nell'anello R
, quindi moltiplichiamo questi elementi insieme e rimandiamo il prodotto agli interi.
return to_ints( to_ring(i)*to_ring(j));
PCLMULQDQ
dall'estensione CLMUL. Sfortunatamente sono stato sottoposto a downgrade per la mia conoscenza dell'istruzione x86 impostata prima (relativa aPEXT/PDEP
), quindi lascerò questo come commento qui.