XOR 곱셈


33

목표는 아래에 정의 된 XOR ( 캐리리스 ) 곱셈 연산을 가능한 한 적은 바이트로 구현하는 것입니다 .

비트 XOR ( ^)을 캐리없이 이진 덧셈으로 생각하면

   101   5
^ 1001   9
  ----  
  1100  12

  5^9=12

@이진 곱셈 을 수행 하지만 비트 XOR을 수행하지 않고 더하기 단계를 수행하여 XOR 곱셈 을 수행 할 수 있습니다 ^.

     1110  14
   @ 1101  13
    -----
     1110
       0
   1110
^ 1110 
  ------
  1000110  70

  14@13=70

(수학자에게는 다항식 고리 의 곱셈으로 Z보다 다항식 F_2[x]으로 평가하여 자연수로 다항식을 식별합니다 x=2.)

XOR 곱셈 은 비트 단위 XOR을 통해 통근 a@b=b@a, 연관 (a@b)@c=a@(b@c)및 분배 a@(b^c)=(a@b)^(a@c)합니다. 실제로, 그것은 a@b=a*b언제나 곱셈 a과 같고 같은 b힘을 갖는 유일한 그러한 연산입니다 .21,2,4,8...

요구 사항

음수가 아닌 두 정수를 입력 및 출력으로 사용하거나 XOR 제품을 인쇄하십시오. 이진 확장이 아니라 숫자 또는 10 진수 문자열 표현이어야합니다. 가장 적은 바이트가 이깁니다.

정수 오버플로에 대해 걱정하지 마십시오.

형식이 다음과 같은 일부 테스트 사례가 a b a@b있습니다.

0 1 0
1 2 2
9 0 0
6 1 6
3 3 5
2 5 10
7 9 63
13 11 127
5 17 85
14 13 70
19 1 19
63 63 1365

13
이것은 "반송없는 곱셈"으로 더 잘 알려져 있으며, 질문 제목을 추가하고 싶을 가능성이 가장 PCLMULQDQ높으며 CLMUL 확장 의 6 바이트 x86 명령어 일 가능성이 가장 높습니다. 불행히도 ( PEXT/PDEP) 전에 x86 명령어 세트에 대한 지식으로 다운 투표를 받았 으므로 여기에 의견으로 남겨 두겠습니다.
Idonotexist Idonotexist

@IwillnotexistIdonotexist 노트를 보내 주셔서 감사합니다. Google에 이름을 지정하는 것이 좋습니다.
xnor

위의 내용이 "xor"가 아닌 경우 xorc 또는 xornc와 다른 방식으로 전화해야합니다. xor가 아닙니다
RosLuP

1
@RosLuP 그것은 xor가 아니며 xor 곱셈입니다.
xnor

@boboquack 사실, 나는 곱셈 곱셈 이 다르다고 생각 합니다. 예를 들어 2 * 2 == 3입니다. 이 두 가지 모두 nim 덧셈에 분포하지만이 챌린지의 곱은 2의 거듭 제곱에 대한 곱셈과 일치하는 반면에 nimber on은 2 ^ (2 ^ n)에만 일치합니다.
xnor

답변:


36

x86 기계 코드 : 7 바이트

66 0F 3A 44 C1 00 C3  pclmulqdq xmm0, xmm1, 0 \ ret

두 가지 지침 만 있습니다. pclmulqdq무거운 리프팅을 수행하면 문자 그대로 해당 유형의 xor- 곱셈을 구현합니다. ret호출 가능한 함수로 만들기 위해 결과를 "출력"하는 요구 사항을 충족시키기를 바랍니다 (반환 값 xmm0). xmmargs에 정수 인수를 넣는 것은 드문 일이지만 나를 용서하기를 바랍니다.


1
속임수 같은 내장 된 조작 음 사용 ...
CJ Dennis

4
@CJDennis Standard Loopholes 메타 포스트에는 금지 여부에 대한 합의가 없습니다. 금지 44 표, 반대 31 표가 있습니다.
isaacg

1
@isaacg 나는 정말로 까다 롭지 않으려 고 노력하고 있지만 문제의 문구는 다음과 같습니다. 귀하의 목표는 XOR (무부하) 곱셈 연산을 구현하는 것입니다 . 이것은 작업 자체를 "구현"하거나 단순히 다른 사람의 기능을 호출합니까? 다른 모든 답변은 종종이 답변의 몇 바이트 이내에 열심히 일합니다. 나는 그것들이 모두 훨씬 영리하고 이것보다 더 많이지지 할 가치가 있다고 생각합니다.
CJ 데니스

8
질문이 너무 사소한 경우 일반적인 CPU에 의해 직접 구현되면 대답을 비난 할 수 없다고 생각합니다. 특히 흥미 롭거나 기억에 남지 않지만 올바른 답변처럼 보입니다. +1.
Vality

9
나는 이것을 해결하기 위해 사용되는 내장 문제에 아무런 문제가 없다.
xnor

14

Z80, 11 바이트

B7 CB 32 30 01 B3 C8 CB 23 18 F6   

코드는 함수로 호출됩니다. abDE(순서는 중요하지 않습니다)와 답은에 저장된 A코드 반환 (어떤 I / O 기능이없는) 경우.

B7      XOR A     //  A^=A (A=0)
CB 32   SRL D     //    CARRY = lsb(D), D>>=1, ZERO = D==0
30 01   JR NC, 1  //    jump 1 byte if not CARRY
B3      XOR E     //      A^=E, ZERO = A==0
C8      RET Z     //    return if ZERO
CB 23   SLA E     //    E<<=1
18 F6   JR -10    //    jump -10 bytes

모든 레지스터가 8 비트이고 1365 mod 256 = 85 (정수 오버플로)이기 때문에 63@63반환되는 것을 제외하고 모든 테스트 입력에 대해 올바른 결과를 생성합니다 85.


10

C, 44 38 바이트

nimi 덕분에 이제 더 적은 6 바이트의 재귀를 사용합니다!

f(a,b){return b?(b&1)*a^f(a*2,b/2):0;}

우리는 함수를 정의 f한다 a, b.

다음과 같이 호출 할 수 있습니다.

printf("%d @ %d = %d\n", 13, 14, f(13, 14));

어떤 출력 :

13 @ 14 = 70

온라인 테스트 사례를 사용해보십시오 !


1
왜 재귀 버전이 f(a,b)={return(b)?(b&1)*a^f(2*a,b/2):0;}아닌가?
nimi

@nimi 아, 영리하다! 그 바보 같은 매개 변수를 제거하는 방법이 있다는 것을 알고있었습니다. 지금 38 바이트가 있습니다. 감사!
BrainSteel

1
44은 여전히 ​​정규 44입니다. :(
Alex A.

입력은 음이 아니므 (b&1)b%2%왼쪽에서 오른쪽으로 우선 순위 수준이 같으 므로 2 바이트를 더 절약 할 수 있습니다 *.
CL-

9

Pyth, 13 12 바이트

uxyG*HQjvz2Z

데모.

uxyG*HQjvz2Z
                  Implicit:
                  z = input()
                  Q = eval(input())
                  Z = 0

       jvz2       The first input, written in base 2, like so: [1, 0, 1, ...
u      jvz2Z      Reduce over the binary representation, starting with 0.
 x                XOR of
  yG              Twice the previous number
    *HQ           and the second input times the current bit.

이전 버전, 13 바이트 :

xFm*vz.&Q^2dQ

데모.


그렇다면 vz두 개의 정수 입력 을 피하는 좋은 방법이 없다고 생각 합니다.
xnor

@xnor 아니오, 불행히도.
isaacg

8

CJam, 14 13 바이트

q~2bf*{\2*^}*

작동 방식 :

먼저 긴 곱셈 결과를 얻은 다음 맨 아래 두 쌍부터 시작합니다.

q~                e# Eval the input. This puts the two numbers on stack
  2b              e# Convert the second number to binary
    f*            e# Multiply each bit of second number with the first number
                  e# This leaves an array with the candidates to be added in the long
                  e# multiplication step
      {    }*     e# Reduce on these candidates. Starting from the bottom
       \2*        e# Bit shift the lower candidate
          ^       e# XOR each other and continue

여기에서 온라인으로 사용해보십시오


7

J, 14 바이트

*/(~://.@)&.#:

용법:

   5 (*/(~://.@)&.#:) 17     NB. enclosing brackets are optional
85

; 설명 (오른쪽에서 왼쪽으로 주로 읽기 uv: 임의의 기능 서)

  • u&.#:u입력 숫자의 이진 표현 벡터에 적용한 다음 결과를 정수 ( u&.v == v_inverse(u(v(input_1), v(input_2))))로 되돌립니다.
  • */제품 ( *데카르트 제품의 입력 (의) /두 개의 바이너리 벡터)
  • v(u@)적용 uv(데카르트의 제품)
  • u/.uDescartes 제품의 모든 대각 대각선에 적용 (대각선은 이진 표현에서 1, 2, ...을 나타냄)
  • ~:/(감소 /()와 XOR 연산 항 대각선 ~:)
  • 마지막 단계는 첫 번째 점이 처리하는 이진 벡터에서 정수를 생성하는 것입니다.

여기에서 온라인으로 사용해보십시오.


5

파이썬 2, 35 바이트

f=lambda m,n:n and n%2*m^f(2*m,n/2)

처럼 전화하십시오 f(13, 14). 비슷한 구문을 가진 대부분의 언어가 이와 비슷한 것으로 수렴한다고 생각합니다.


4

자바, 62

(x,y)->{int r=0,i=0;for(;i<32;)r^=x*((y>>i)%2)<<i++;return r;}

넓히는

class XORMultiplication {
    public static void main(String[] args) {
        IntBinaryOperator f = (x, y) -> {
                    int r = 0, i = 0;
                    for (; i < 32;) {
                        r ^= x * ((y >> i) % 2) << i++;
                    }
                    return r;
                };
        System.out.println(f.applyAsInt(14, 13));
    }
}

1
당신이 선호하는 이유 for(;i<32;)while(i<32)있습니까? 그것들은 같은 길이이지만 두 번째는 그것을 작성하는 더 자연스러운 방법처럼 보입니다.
JohnE

1
@ JohnE 나는 i++원래 for루프에 있었고 현재 위치로 골프를 쳤다고 생각합니다 . 이후 while되지 않은 작은을 변경할 이유가 없습니다.
CJ 데니스

3

하스켈, 50 바이트

import Data.Bits
_#0=0
a#b=b.&.1*a`xor`2*a#div b 2

@BrainSteel의 C 답변 번역. 사용 예 :

map (uncurry (#)) [(0,1),(1,2),(9,0),(6,1),(3,3),(2,5),(7,9),(13,11),(5,17),(14,13),(19,1),(63,63)]
[0,2,0,6,5,10,63,127,85,70,19,1365]

3

펄-35 바이트

#!perl -p
$\^=$`>>$_&1&&$'<<$_ for-/ /..31}{

명령 행 옵션을 하나로 계산합니다. 입력은STDIN공백으로 구분 받습니다.

샘플 사용법 :

$ echo 13 11 | perl xormul.pl
127
$ echo 5 17 | perl xormul.pl
85
$ echo 14 13 | perl xormul.pl
70
$ echo 19 1 | perl xormul.pl
19
$ echo 63 63 | perl xormul.pl
1365

3

줄리아, 35 33 30 바이트

f(a,b)=b%2*a$(b>0&&f(2a,b÷2))

이것은 재귀 함수를 만듭니다 f 두 개의 정수를 취하고 입력의 XOR 곱을 리턴 를 .

언 골프 드 :

function f(a, b)
    # Bitwise XOR : $
    # Short-circuit AND : &&

    b % 2 * a $ (b > 0 && f(2a, b ÷ 2))
end

Sp3000의 격려로 몇 바이트를 절약했습니다!


2

파이썬 2, 104 91 78 66 바이트

def y(a,b,c=0):
 for _ in bin(b)[:1:-1]:c^=int(_)*a;a<<=1
 print c

문자열의 시작 부분 b을 누르기 전에 끝나는 비트를 역순으로 가져 '0b'갑니다. 곱해 각 axor전체로는 다음 왼쪽 시프트 a. 그런 다음 합계를 인쇄하십시오.



2

간격 , 368 바이트

수학자의 경우, 이것은 다항식 고리 F_2 [x]의 곱셈으로, x보다 2에서 Z에 대한 다항식으로 평가하여 자연수로 다항식을 식별합니다.

물론하자! (이것은 느슨하게 골프를 쳤으며, 요점은 F 2 [x] 로 옮기고 우승작이 되려는 시도보다 더 많은 계산을 수행하는 것입니다)

코드는 다음과 같습니다

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;

설명이 포함 된 ungolfed 코드는 다음과 같습니다.

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;

좋아, 첫째로, 우리는 필드 F를 통해 단 변수 다항식 링 만들고 2 및 호출 R. 참고 GF(2)F 인 2 GAP있다.

R:=PolynomialRing(GF(2));

다음으로 GAP 변수 x를 ring의 결정에 할당합니다 R. 이제 xGAP에서 말할 때마다 시스템은 반지의 불확정성에 대해 이야기하고 있음을 알 수 R있습니다.

x:=IndeterminatesOfPolynomialRing(R);
x:=x[1];

다음으로, 우리는 서로 역맵되는 두 개의 함수를가집니다. 이 맵은 모두 있지만 구조 보존은 아니므로 GAP에서 더 나은 방법을 구현할 수 없었습니다. 당신이 그것을 알고 있다면 의견을 말하십시오!

첫 번째 맵 to_ring은 정수를 가져와 해당 링 요소에 매핑합니다. 그것은 모든 바이너리 알고리즘에 대한 변환을 사용하여이 작업을 수행 1진에 나타날 것이라고는로 대체 x^n어디 n수 실제로 바이너리 인 경우 (2)가 수행하게되는 적절한 전원입니다.

    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;

다음 함수는 이것을 반대로합니다. to_ints링 요소를 가져와 해당 정수에 매핑합니다. 나는 다항식의 계수 목록을 가져 와서 0이 아닌 각 계수에 대해 결과를 2 ^ n 씩 증가시킵니다. 이진수를 10 진수로 변환하는 것과 같습니다.

    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;

마지막 단계에서는 이러한 함수를 호출합니다. 우리는 두 개의 정수 입력을 가져 와서 링의 요소로 변환 R한 다음이 요소를 곱한 다음 곱을 정수로 다시 보냅니다.

return to_ints( to_ring(i)*to_ring(j));

1

루비, 76 75 73 바이트

a,b=$*.map{|x|x.to_i}
o=0
while(b>0)
o^=a&-(b&1)
a<<=1
b>>=1
end
puts(o)

루비, 60 바이트 (기능 만, I / O 없음)

def t(a,b)
o=0
while(b>0)
o^=a&-(b&1)
a<<=1
b>>=1
end
t
end


1

다트, 34 32 바이트

m(a,b)=>a<1?0:a%2*b^m(a~/2,b*2);

간단한 재귀 구현.



1

GNU 어셈블러 (x86_64 Mac OS X), 97 바이트

이것은 C에서 호출 할 수있는 적절한 함수입니다.

.text
.globl _f
_f:
movq %rdi,%xmm0;movq %rsi,%xmm1;pclmulqdq $0,%xmm1,%xmm0;movq %xmm0,%rax;ret

이 C 프로그램으로 테스트 할 수 있습니다 :

#include <stdio.h>
int f(int a, int b);
#define p(a,b) printf("%d %d %d\n", a, b, f(a, b))
int main(void)
{
    p(0,1);
    p(1,2);
    p(9,0);
    p(6,1);
    p(3,3);
    p(2,5);
    p(7,9);
    p(13,11);
    p(5,17);
    p(14,13);
    p(19,1);
    p(63,63);
}

Mac OS X에서는 다음을 사용해야합니다. clang -x c C ++이 아닌 C로 컴파일해야합니다.

리눅스의 경우 (정확하게 기억한다면) 코드는 95 바이트입니다.

.text
.globl f
f:
movq %rdi,%xmm0;movq %rsi,%xmm1;pclmulqdq $0,%xmm1,%xmm0;movq %xmm0,%rax;ret

이상하게도,이 버전은 실제로 인라인 어셈블리에서 함수를 정의하는 것보다 길지만 그 버전은 이미 가지고있는 순수한 C 솔루션보다 길기 때문에 어셈블리를 시도하기로 결정했습니다.

편집하다

조립 된 크기 (라벨 & c. 제외)로 계산하면

x86_64 어셈블러, 22 바이트 :

0:  66 48 0f 6e c7          movq         %rdi,  %xmm0
5:  66 48 0f 6e ce          movq         %rsi,  %xmm1
a:  66 0f 3a 44 c1 00       pclmullqlqdq $0,    %xmm1,%xmm0
10: 66 48 0f 7e c0          movq         %xmm0, %rax
15: c3                      ret

그래도 컴파일 된 형식으로 어셈블리 언어를 측정한다고 생각합니다.
Nissa

0

golflua 68

x,y=I.r("*n","*n")r=0~@i=0,31r=B.x(r,x*B.ls(B.rs(y,i)%2,i+1))$w(r/2)

기본적으로 Ypnypn의 Java answer 와 동일한 비트 이동이 있지만 올바르게 작동하려면 마지막에 2로 나누기를 요구하는 것 같습니다. stdin으로 값을받습니다 (아래 예).

> 14 13 
70
> 19 1 
19
> 5 17 
85

0

실론, 90 바이트

alias I=>Integer;I x(I a,I b)=>[for(i in 0:64)if(b.get(i))a*2^i].fold(0)((y,z)=>y.xor(z));

곱셈 :이 설명 된 바와 같이 단지 알고리즘 a에 의해 2^ii번째 비트가 설정되어 b, 및 XOR을 사용하여 모두 함께 추가합니다. 0:64JVM에서 실행될 때 정수가 Ceylon에서 64 비트이기 때문에 반복 됩니다 (Javascript로 실행할 때는 낮지 만b.get(i) 만 false를 리턴 함).

형식화 :

alias I => Integer;

I x(I a, I b) =>
      [
        for (i in 0:64)
            if (b.get(i))
                a * 2^i
      ].fold(0)((y, z) => y.xor(z));

별명은 여기에서 단일 바이트 만 보호합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.