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   

코드는 함수로 호출됩니다. a과 b에 D와 E(순서는 중요하지 않습니다)와 답은에 저장된 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

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

  • u&.#:u입력 숫자의 이진 표현 벡터에 적용한 다음 결과를 정수 ( u&.v == v_inverse(u(v(input_1), v(input_2))))로 되돌립니다.
  • */제품 ( *데카르트 제품의 입력 (의) /두 개의 바이너리 벡터)
  • v(u@)적용 u에 v(데카르트의 제품)
  • 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'갑니다. 곱해 각 a및 xor전체로는 다음 왼쪽 시프트 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^i곳 i번째 비트가 설정되어 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.