GAP , 368 Bytes
Für Mathematiker ist dies die Multiplikation im Polynomring F_2 [x], wobei Polynome mit natürlichen Zahlen identifiziert werden, indem bei x = 2 als Polynom über Z ausgewertet wird.
Klar, lass uns das machen! (Dies ist nur locker gespielt, es ging mehr darum, in F 2 [x] einzusteigen und die Berechnungen durchzuführen, als jeden Versuch, ein Gewinner zu sein.)
Hier ist der Code
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;
Hier ist der ungolfed Code mit Erklärung:
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;
Okay, also erstellen wir zuerst den univariaten Polynomring über dem Feld F 2 und nennen ihn R
. Beachten Sie, dass in GAP GF(2)
F 2 ist .
R:=PolynomialRing(GF(2));
Als nächstes werden wir die GAP-Variable x
der Unbestimmtheit des Rings zuweisen R
. Wenn ich jetzt x
in GAP sage , weiß das System, dass ich von der Unbestimmtheit des Rings spreche R
.
x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];
Als nächstes haben wir zwei Funktionen, die Inverse Maps voneinander sind. Diese Karten sind beide in, aber sie sind nicht strukturerhaltend, sodass ich mir keinen besseren Weg vorstellen kann, sie in GAP zu implementieren. Es gibt mit ziemlicher Sicherheit einen besseren Weg, wenn Sie es wissen, bitte kommentieren Sie!
Die erste Map to_ring
nimmt eine Ganzzahl und ordnet sie dem entsprechenden Ringelement zu. Dies geschieht durch eine Konvertierung in einen Binäralgorithmus, bei dem jedes 1
, was in einer Binärzahl erscheint, durch ein ersetzt wird, x^n
wo n
die entsprechende Potenz ist, die 2 annehmen würde, wenn die Zahl tatsächlich binär wäre.
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;
Die nächste Funktion kehrt dies um. to_ints
Nimmt ein Ringelement und ordnet es der entsprechenden Ganzzahl zu. Dazu erhalte ich eine Liste der Koeffizienten des Polynoms, und für jeden Koeffizienten ungleich Null wird das Ergebnis um 2 ^ n erhöht, auf dieselbe Weise, wie wir Binär in Dezimal umwandeln würden.
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;
Im letzten Schritt rufen wir diese Funktionen auf. Wir nehmen die beiden Ganzzahleingaben, konvertieren sie in Elemente im Ring R
, multiplizieren diese Elemente dann und senden das Produkt zurück zu den Ganzzahlen.
return to_ints( to_ring(i)*to_ring(j));
PCLMULQDQ
aus der CLMUL-Erweiterung. Leider wurde ich für mein Wissen über den x86-Befehlssatz vor (Related toPEXT/PDEP
) abgelehnt , daher werde ich dies hier nur als Kommentar hinterlassen.