XOR çarpımı


33

Amacınız, aşağıda tanımlanan XOR ( carryless ) çarpım işleminin mümkün olduğu kadar az baytta gerçekleştirilmesidir .

Bitsel olarak XOR ( ^) ' yu taşıt olmadan ikili toplama olarak düşünürsek

   101   5
^ 1001   9
  ----  
  1100  12

  5^9=12

XOR çarpımını @ikili uzun çarpım yaparak ancak bit yönünde XOR olarak taşımadan ekleme işlemini yaparak yapabiliriz ^.

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

  14@13=70

(Matematikçiler için, bu polinom halkasında çarpma, Z'den çok polinom olarak F_2[x]değerlendirilerek doğal sayılarla polinomları belirlemedir x=2.)

XOR çarpımı bitsel XOR üzerinden işlem yapar a@b=b@a, ilişkilendirir (a@b)@c=a@(b@c)ve dağıtır a@(b^c)=(a@b)^(a@c). Aslında, a@b=a*bne zaman ne olursa olsun ave benzeri bgüçlerin çarpımıyla eşleşen eşsiz bir işlemdir .21,2,4,8...

Gereksinimler

Negatif olmayan iki tam sayıyı giriş ve çıkış olarak alın veya XOR ürünlerini yazdırın. Bu, ikili genişlemeleri değil, sayılar veya ondalık dizgi gösterimleri olmalıdır. En az bayt kazanır.

Tamsayı taşmaları konusunda endişelenmeyin.

İşte olarak biçimlendirilmiş bazı test durumları 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
Bu, soru başlığını eklemek isteyebileceğiniz "taşıma gerektirmeyen çarpma" olarak bilinir ve yüksek olasılıkla en küçük giriş, PCLMULQDQCLMUL uzantısından gelen 6 bayt x86 komutudur. Maalesef önceden ayarlanmış x86 komutları hakkındaki bilgilerimden dolayı hak kazandım ( PEXT/PDEPBu konuda), bu yüzden burada sadece yorum olarak bırakacağım.
Idonotexist,

@IwillnotexistIdonotexist Not için teşekkürler, Google’a bir ad vermek güzel.
xnor

Eğer yukarıdaki "xor" değilse, xorc veya xornc olarak farklı şekilde çağırmanız gerekir ... xor değil
RosLuP

1
@RosLuP Bu xor değil, xor çarpımı.
xnor

@boboquack Aslında, nimber çarpımının farklı olduğuna inanıyorum . Örneğin, 2 * 2 == 3. Bunların her ikisi de nim ilavesi üzerinde dağılır, fakat bu mücadeledeki olanı 2 güçlerin çarpımıyla eşleşir, oysa nozüller sadece 2 ^ (2 ^ n) ile eşleşir.
xnor

Yanıtlar:


36

x86 makine kodu: 7 bayt

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

Sadece iki talimat. pclmulqdqağır kaldırma yapar, tam anlamıyla bu tür xor-çarpımı uygular. retçağrılabilir bir işlev yapmak için, umarım "çıktı" ("geri dönüş değerinde") gereksinimini karşılar xmm0. Tamsayı argümanlarını argümanlara koymak xmmbiraz sıra dışıdır, ancak umarım beni affedersiniz.


1
Dahili bir işlem kullanmak hile gibi geliyor ...
CJ Dennis

4
@CJDennis Standart Loopholes meta mesajında, yasaklanıp kapatılmayacağı konusunda fikir birliği yoktur. Yasaklama için 44, aleyhte 31 oy var.
isaacg,

1
@isaacg Gerçekten çok seçici olmaya çalışmıyorum ama sorunun ifadesi şudur: Amacınız XOR (taşınmaz) çarpma işleminin uygulanmasıdır . Bu cevap işlemi "uygular" mı yoksa basitçe başkasının işlevini mi çağırıyor? Diğer tüm cevaplar, genellikle bu cevabın birkaç baytı içinde, sıkı çalışmayı kendileri yapar. Bence hepsi çok daha zeki ve bundan daha fazlasını hak ediyorlar.
CJ Dennis

8
Eğer soru çok önemsiz ise doğrudan ortak bir CPU tarafından uygulanıyorsa, bir cevabı suçlayabileceğimi gerçekten hissetmiyorum, bundan daha düşük bir seviye elde edilemiyor. Bu özellikle ilginç veya unutulmaz değildir, ancak geçerli bir cevap gibi görünmektedir, yani +1.
Vality

9
Bunu çözmek için kullanılan bir cihazla ilgili bir sorunum yok - aksi halde, böyle bir yerleşik varlığın olduğunu bilemezdim.
xnor

14

Z80, 11 bayt

B7 CB 32 30 01 B3 C8 CB 23 18 F6   

Kod bir işlev olarak adlandırılır. ave biçindedir Dve E(sipariş önemli değildir) ve cevap saklanır Akod döndürür (hayır I / O fonksiyonları vardır) ne zaman.

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

Tüm kayıtlar 8-bit ve 1365 mod 256 = 85 (tamsayı taşma) olduğundan 63@63geri dönüşler hariç tüm test girişi için doğru sonuçları üretir 85.


10

C, 44 38 bayt

Nimi sayesinde şimdi 6 daha az bayt için özyineleme kullanıyoruz!

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

Biz bir işlev tanımlamak falır a, b.

Bu gibi çağrılabilir:

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

Hangi çıktılar:

13 @ 14 = 70

Test vakalarını çevrimiçi olarak deneyin !


1
Neden özyinelemeli bir sürüm değil f(a,b)={return(b)?(b&1)*a^f(2*a,b/2):0;}?
nimi

@ nimi Ah, zeki! O aptal parametreden kurtulmanın bir yolu olduğunu biliyordum. Şimdi 38 bayt var. Teşekkürler!
BrainSteel

1
44 Struck hala normal 44. :(
Alex A.

Girişler negatif değildir, böylece soldan sağa aynı önceliğe sahip olduğundan , iki bayt daha kaydetmek için (b&1)ile değiştirebilirsiniz . b%2%*
CL

9

Pyth, 13 12 bayt

uxyG*HQjvz2Z

Gösteri.

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.

Eski versiyon, 13 bayt:

xFm*vz.&Q^2dQ

Gösteri.


Sanırım vziki tamsayı girişi almaktan kaçınmanın iyi bir yolu yok .
xnor

@xnor Hayır, ne yazık ki.
isaacg

8

CJam, 14 13 bayt

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

Nasıl çalışır :

İlk önce uzun çarpma sonuçlarını alıyoruz ve sonra en alttaki iki çiftten başlayarak yukarı doğru çalışıyoruz.

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

Burada çevrimiçi deneyin


7

J, 14 bayt

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

Kullanımı:

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

Açıklama (çoğunlukla sağdan sola okuma uve vkeyfi işlevlerin yerine getirilmesi):

  • u&.#:ugiriş sayılarının ikili gösterimlerinin vektörleri için geçerlidir , ardından sonucu bir tamsayıya ( u&.v == v_inverse(u(v(input_1), v(input_2)))) döndür
  • */İkili vektörün *Descartes ürünündeki ( /) girdilerinin ürünleri ( )
  • v(u@)uygulamak uiçin v(Descartes ürüne)
  • u/.uDescartes ürününün her köşegenine uygulanır (köşegenler, ikili göstergede 1., 2., ... basamağı temsil eder)
  • ~:/küçültmek ( /) XOR işlemiyle bir çapraz-köşegen ( ~:)
  • Son adım, ilk noktanın ilgilendiği ikili vektörden bir tam sayı oluşturmaktır.

Burada çevrimiçi deneyin.


5

Python 2,35 bayt

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

Gibi ara f(13, 14). Bence benzer bir yapıya sahip dillerin çoğu bunun gibi birşeye yaklaşacak.


4

Java, 62

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

Expanded

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
Eğer tercih bir nedeni var mı for(;i<32;)hiç while(i<32)? Aynı uzunluktadırlar, ancak ikincisi onu yazmak için daha doğal bir yol gibi görünüyor.
JohnE

1
@JohnE Bunun i++asıl fordöngüde olduğunu ve şu anki pozisyonunda golf oynadığını tahmin ediyorum . Daha whileküçük olmadığından değiştirmek için sebep yok.
CJ Dennis

3

Haskell, 50 bayt

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

@ BrainSteel'in C cevabının çevirisi. Kullanım örneği:

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

Perl - 35 bayt

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

Komut satırı seçeneğini tek olarak sayma. Giriş STDIN, alandan ayrılarak alınır .

Örnek kullanım:

$ 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

Julia, 35 33 30 bayt

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

Bu, fiki tam sayı alan ve girdilerin XOR ürününü döndüren özyinelemeli bir işlev yaratır .

Ungolfed:

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

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

Sp3000 cesaretlendirmeli bir kaç byte kurtarıldı!


2

Python 2, 104 91 78 66 bayt

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

Bitleri bters sırayla alın, '0b'dizenin başlangıcına basmadan önce biter . Çarpma her biri ave xortoplam, daha sonra sol kayma a. Sonra toplamı yazdırın.



2

GAP , 368 Bayt

Matematikçiler için bu, F_2 [x] polinom halkasında çarpma olup, x = 2'de Z üzerinden bir polinom olarak değerlendirilerek doğal sayılarla polinomları tanımlar.

Tabii, hadi yapalım şunu! (bu sadece loosly golfed olup, nokta F taşımak more 2 [x] 've kazanan bir giriş olarak herhangi bir girişim çok daha hesaplamaları yapmak)

İşte kod

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;

İşte açıklama ile ungolfed kodu:

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;

Tamam, ilk olarak, biz bu alanda F üzerinde tek değişkenli polinom halkası oluşturmak 2 ve diyoruz R. GAP'ta GF(2)F 2 olduğuna dikkat edin .

R:=PolynomialRing(GF(2));

Daha sonra, GAP değişkenini xhalkanın belirsizine atayacağız R. Şimdi, ne zaman xGAP'ta söylesem , sistem halkanın belirsizliğinden bahsettiğimi bilecek R.

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

Sonra, birbirimizin ters haritası olan iki işleve sahibiz. Bu haritalar her ikisinde de var, ancak bunlar yapıyı koruyamıyorlar, bu yüzden GAP'ta uygulamak için daha iyi bir yol bulamadım. Neredeyse kesinlikle daha iyi bir yol var, eğer biliyorsanız, lütfen yorum yapın!

İlk harita, to_ringbir tamsayı alır ve onu ilgili halka elemanına eşler. Her ikili algoritma, bir dönüşüm kullanarak gerçekleştirir 1ikili katılacağını bir değiştirilir x^nnerede nnumara gerçekten de ikili olsaydı 2 alacağını uygun gücüdür.

    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;

Bir sonraki işlev bunu tersine çevirir. to_intsbir halka elemanı alır ve karşılık gelen tamsayıya eşler. Bunu, polinomun katsayılarının bir listesini alarak ve sıfır olmayan her katsayı için ikilik ondalık sayıya dönüştürdüğümüz gibi sonuç 2 ^ n artırıyor.

    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;

Son adım için bu fonksiyonları çağırıyoruz. İki tamsayı girişini alıyoruz, bunları halkadaki elementlere dönüştürüyoruz R, sonra bu elemanları bir araya çarpıyoruz ve ürünü tekrar tamsayılara gönderiyoruz.

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

1

Ruby, 76 75 73 bayt

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

Ruby, 60 bayt (yalnızca işlev, G / Ç yok)

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


1

Dart, 34 32 bayt

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

Düz ileri özyinelemeli uygulama.


1

gnuplot, 29 bayt

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

sadece Dart'daki gibi (yukarıya bakın)


1

GNU Birleştirici (x86_64 Mac OS X), 97 bayt

Bu, C'den çağrılabilecek uygun bir işlevdir:

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

& Bu C programı ile test edilebilir:

#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'te clang -x cC & C ++ değil derlemek için kullanmanız gerektiğini unutmayın.

Linux için (doğru hatırlıyorsam) kod 95 bayt olacaktır:

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

Garip bir şekilde, bu sürüm aslında satır içi derlemede işlevi tanımlamaktan daha uzun, ancak bu zaten sahip olduğumuz saf C çözümünden daha uzundu, bu yüzden derlemeyi denemeye karar verdim.

Düzenle

Birleştirilmiş boyutta sayılıyorsa (herhangi bir etiket ve c hariç)

x86_64 Assembler, 22 bayt:

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

Meclis dillerini derlenmiş formlarına göre ölçeceğinizi düşünüyorum.
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)

Temelde, Ypnypn'in Java cevabı ile aynı bit değiştirmeyi yapar , ancak sonunda doğru çalışabilmesi için 2'ye bölünmeyi gerektiriyor gibi görünmektedir. Stdin olarak değerleri alır, aşağıdaki örnekler

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

0

Seylan, 90 bayt

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));

Çarpma: Bu tarif edildiği gibi sadece algoritmadır atarafından 2^iher yerde iinci bit ayarlanır bve xor kullanarak tüm bunları birbirine ekleyin. Üzerinde yinelenir0:64Integers, JVM üzerinde çalışırken 64-bit olduğundan (Javascript olarak çalışırken daha düşük, ancak daha sonra b.get(i)false değerini döndürür) tekrar eder.

biçimlendirilmiş:

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));

Takma ad burada yalnızca bir bayt olarak güvenlidir.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.