GAP , 368 octets
Pour les mathématiciens, il s'agit d'une multiplication dans l'anneau polynomial F_2 [x], identifiant les polynômes avec des nombres naturels en évaluant à x = 2 en tant que polynôme sur Z.
Bien sûr, faisons ça! (Ce n'est que vaguement joué au golf, le but était plutôt de passer à F 2 [x] et de faire les calculs plus que toute tentative d'être une entrée gagnante)
Voici le 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;
Voici le code non-golfé avec explication:
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;
D'abord, nous créons l'anneau polynomial univarié sur le corps F 2 et l'appelons R
. Notez que GF(2)
c'est F 2 dans GAP.
R:=PolynomialRing(GF(2));
Ensuite, nous allons affecter la variable GAP x
à l'indéterminé de l'anneau R
. Maintenant, chaque fois que je dis x
dans GAP, le système saura que je parle de l'indétermination de la bague R
.
x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];
Ensuite, nous avons deux fonctions, qui sont des cartes inverses l’une de l’autre. Ces cartes sont sur les deux, mais elles ne préservent pas la structure, donc je ne pouvais pas trouver un meilleur moyen de les implémenter dans GAP. Il y a presque certainement une meilleure solution. Si vous le savez, veuillez commenter!
La première carte, to_ring
prend un entier et le mappe à l'élément anneau correspondant. Pour ce faire, il utilise un algorithme de conversion en binaire, où tout 1
ce qui apparaît en binaire est remplacé par un x^n
où n
est la puissance appropriée que 2 prendrait si le nombre était effectivement binaire.
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 fonction suivante inverse cela. to_ints
prend un élément en anneau et le mappe sur son entier correspondant. Je le fais en obtenant une liste des coefficients du polynôme et, pour chaque coefficient non nul, le résultat est augmenté de 2 ^ n, de la même manière que nous convertirions les valeurs binaires en valeurs décimales.
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;
Pour la dernière étape, nous appelons ces fonctions. Nous prenons les deux entrées entières, les convertissons en éléments dans l'anneau R
, puis multiplions ces éléments ensemble et renvoyons le produit aux entiers.
return to_ints( to_ring(i)*to_ring(j));
PCLMULQDQ
de l'extension CLMUL. Malheureusement, ma connaissance du jeu d'instructions x86 a déjà été votéePEXT/PDEP
, je vais donc laisser cela comme un commentaire.