GAP , 368 byte
Đối với các nhà toán học, đây là phép nhân trong vòng đa thức F_2 [x], xác định đa thức với số tự nhiên bằng cách đánh giá tại x = 2 là đa thức trên Z.
Chắc chắn, hãy làm điều đó! (đây chỉ là môn đánh gôn lỏng lẻo, điểm quan trọng hơn là di chuyển vào F 2 [x] và thực hiện các phép tính nhiều hơn bất kỳ nỗ lực nào để trở thành một mục thắng)
Đây là mã
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;
Đây là mã không được giải thích với lời giải thích:
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;
Được rồi, trước hết, chúng ta tạo vòng đa thức đơn biến trên trường F 2 và gọi nó R
. Lưu ý rằng đó GF(2)
là F 2 trong GAP.
R:=PolynomialRing(GF(2));
Tiếp theo, chúng ta sẽ gán biến GAP x
cho phần không xác định của vòng R
. Bây giờ, bất cứ khi nào tôi nói x
trong GAP, hệ thống sẽ biết tôi đang nói về sự không xác định của chiếc nhẫn R
.
x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];
Tiếp theo, chúng ta có hai chức năng, đó là các bản đồ nghịch đảo của nhau. Các bản đồ này đều nằm trên, nhưng chúng không bảo tồn cấu trúc, vì vậy tôi không thể tìm ra cách nào tốt hơn để thực hiện chúng trong GAP. Gần như chắc chắn là một cách tốt hơn, nếu bạn biết điều đó, xin vui lòng bình luận!
Bản đồ đầu tiên, to_ring
lấy một số nguyên và ánh xạ tới phần tử vòng tương ứng của nó. Nó làm điều này bằng cách sử dụng một chuyển đổi thuật toán nhị phân, nơi mỗi 1
đó sẽ xuất hiện trong hệ nhị phân được thay thế bằng một x^n
nơi n
là sức mạnh thích hợp mà 2 sẽ thực hiện nếu con số này là thực sự nhị phân.
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;
Các chức năng tiếp theo đảo ngược điều này. to_ints
lấy một phần tử vòng và ánh xạ nó tới số nguyên tương ứng của nó. Tôi làm điều này bằng cách lấy danh sách các hệ số của đa thức và với mỗi hệ số khác 0, kết quả được tăng thêm 2 ^ n, giống như cách chúng ta sẽ chuyển đổi nhị phân thành thập phân.
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;
Đối với bước cuối cùng, chúng tôi gọi các chức năng này. Chúng tôi lấy hai đầu vào số nguyên, chuyển đổi chúng thành các phần tử trong vòng R
, sau đó nhân các phần tử này lại với nhau và gửi sản phẩm trở lại số nguyên.
return to_ints( to_ring(i)*to_ring(j));
PCLMULQDQ
từ phần mở rộng CLMUL. Thật không may, tôi đã bị đánh giá thấp về kiến thức của mình về tập lệnh x86 trước đó (Liên quan đếnPEXT/PDEP
), vì vậy tôi sẽ chỉ để lại nhận xét này ở đây.