8 bitlik bir toplayıcı uygulayın


12

Meydan okuma

Değerleri 0 - 255 arasında olan ve bu tamsayı mod 256'nın toplamını döndüren iki tamsayıyı kabul eden bir işlev uygulayın. Sadece bitsel olumsuzlama (~), bitsel veya (|), bit kaydırma operatörlerini (>>, <<) kullanabilirsiniz. ve atama (=).

Kullanamayacağınız şeyler şunları içerir (ancak bunlarla sınırlı değildir)

  • Toplama, çıkarma, çarpma ve bölme
  • döngüler
  • Koşullu ifadeler
  • İşlev çağrıları

İkili veya ikili negatifleme ve bit kaydırma işlemlerinin en az kullanımı kazanır . Beraberlik durumunda, en popüler çözüm kazanır. Her zaman olduğu gibi standart boşluklar uygulanır.

İşte basit bir 2-bit toplayıcı örneği. Toplam 107 puan için 77 ikili negatif, 28 ikili ors ve 2 bit kaydırma kullanır (bu, C ön işlemcisinin çalıştırılmasıyla görülebilir gcc -E). Leri kaldırarak #defineve elde edilen ifadeleri basitleştirerek çok daha verimli hale getirilebilirdi , ancak bunları netlik için bıraktım.

#include <stdio.h>

#define and(a, b) (~((~a)|(~b)))
#define xor(a, b) (and(~a,b) | and(a,~b))

int adder(int a, int b)
{
    int x, carry;
    x = xor(and(a, 1), and(b, 1));
    carry = and(and(a, 1), and(b, 1));
    carry = xor(xor(and(a, 2), and(b, 2)), (carry << 1));
    x = x | carry;
    return x;
}

int main(int argc, char **argv)
{
    int i, j;
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            if (adder(i, j) != (i + j) % 4) {
                printf("Failed on %d + %d = %d\n", i, j, adder(i, j));
            }
        }
    }
}

Güncelleme: Örnek eklendi ve puanlama ölçütünü değiştirdi


2
neden bitsel "ve" değil?
rdans

@Ryan Çoğu insan NAND kapılarına NOR kapılarına göre daha aşinadır :)
Orby

1
özyineleme bir döngü olarak sayılır?
rdans

@Ryan Recursion bir döngü olarak sayılır, ancak koşullu bir ifade olmadan nasıl uygulayacağınızdan emin değilim.
Orby

Taşma tanımlı mı yoksa taşma durumunda herhangi bir çıktı alabilir miyim?
Komintern

Yanıtlar:


8

Python, 36 işlem

"8" parametresinde logaritmik bir yöntem!

def add(a,b):
    H = a&b   #4 for AND
    L = a|b   #1 
    NX = H | (~L) #2
    K = NX 

    H = H | ~(K | ~(H<<1)) #5
    K = K | (K<<1) #2

    H = H | ~(K | ~(H<<2)) #5
    K = K | (K<<2) #2

    H = H | ~(K | ~(H<<4)) #5

    carry = H<<1 #1

    neg_res = NX ^ carry  #7 for XOR
    res_mod_256 = ~(neg_res|-256) #2
    return res_mod_256

Fikir, hangi endekslerin taştığını ve neden olduğuna karar vermektir. Başlangıçta, bu ikisi sadece yeridir aandd bbir var 1. Ancak, taşınan bitler daha fazla taşmaya neden olabileceğinden, bunun tekrar tekrar belirlenmesi gerekir.

Her dizinin bir sonrakine taşması yerine, bir taşma işleminin (H) ve taşma işleminin artık yapılamadığı yerleri (K) hatırladığımızdan emin olarak, 1 endeks, sonra 2 endeks, sonra 4 endeks taşıyarak süreci hızlandırırız (K ).


47 işlemle daha basit bir yinelemeli çözüm :

def add(a,b):
    H = a&b   #4 for AND
    L = a|b   #1 
    NX = H | (~L) #2

    c=H<<1  #1

    for _ in range(6): #6*5
        d = (~c)|NX
        e = ~d
        c = c|(e<<1)

    res = c ^ NX  #7 for XOR

    res_mod_256 = ~(res|-256) #2
    return res_mod_256

Test teçhizatı, kopyalamak isteyen herkes için.

errors=[]
for a in range(256):
    for b in range(256):
        res = add(a,b)
        if res!=(a+b)%256: errors+=[(a,b,res)]

print(len(errors),errors[:10])

9

C - 0

~, |, >>, << ve = dışında işleçler kullanıyor, ancak döküm ve virgül işleçlerini kullanarak çözümler görüyorum, bu yüzden yasak operatörleri kullanmadığı sürece kuralın çok katı olmadığını tahmin ediyorum.

unsigned char sum(unsigned char x, unsigned char y)
{
    static unsigned char z[] = {
        0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
        16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
        32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
        48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
        64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
        80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
        96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
        112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
        128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
        144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
        160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
        176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
        192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
        208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
        224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
        240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
        0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
        16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
        32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
        48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
        64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
        80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
        96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
        112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
        128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
        144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
        160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
        176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
        192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
        208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
        224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
        240,241,242,243,244,245,246,247,248,249,250,251,252,253,254
    };

    return (&z[x])[y];
}

Bu açık bir boşluk ama işaret etmek için +1.
Orby

7

python, skor = 83 80

def g(x,y):
    for i in xrange(7):
        nx = ~x
        ny = ~y
        x,y = ~(x|ny)|~(nx|y), (~(nx|ny))<<1
    x = ~(x|~y)|~(~x|y)
    return ~(~x|256)

Döngüyü açın. Her döngü süresi için 10 ops 7 döngü, son xor için 7 ve sondaki 9. biti ezmek için 3'tür.

Denklemi x+y = x^y + 2*(x&y)8 kez tekrarlayarak uygular . Her seferinde bir sıfır bit daha var y.


7

C, Puan: 77 60

Sadece o cehennemi için golfed 206 169 131 bayt:

#define F c=((~(~c|~m))|n)<<1;
a(x,y){int m=(~(x|~y))|~(~x|y),n=~(~x|~y),c;F F F F F F F return (unsigned char)(~(m|~c))|~(~m|c);}

Expanded:

int add(x,y)
{
    int m=(~(x|~y))|~(~x|y);
    int n=~(~x|~y);
    int c = 0;
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1;    
    c=((~(~c|~m))|n)<<1; 
    c=((~(~c|~m))|n)<<1; 
    return (int)((unsigned char)(~(m|~c))|~(~m|c));
}

Esasen @KeithRandall @JuanICarrano ile aynı çözüm (matematiksel olarak) ortaya çıktı, ancak C'nin değişken tipler ve işaretçilerle hızlı ve gevşek oynama yeteneğinden yararlanarak ilk 8 bitten sonra herhangi bir operatör kullanmadan faydalanın.

Makinenin endianitesine ve bir int ve bir char boyutuna () bağlıdır, ancak uygun işaretçi matematiği ile makineye özgü uygulamaların çoğuna taşınabilmelidir.

DÜZENLEME: Bu, birisinin taşıması gerekmeyen bir algoritma bulmazsa, C'nin (veya diğer düşük seviyeli dillerin) belirgin bir üst ele sahip olacağı bir zorluktur.


Sargıyı bu şekilde idare edecekseniz, sadece atlayabilirsiniz unsigned char. Daha temiz ve daha taşınabilir.
Orby

@Orby - Sanırım yazarak unsignedkod golf doğal bana gelmiyor. Tabii ki haklısın - güncellendi.
Komintern

4

Python - Puan 66 64

def xand(a,b):
    return ~(~a|~b) #4

def xxor(a,b):
    return (~(a|~b))|~(~a|b) #7

def s(a,b):
    axb = xxor(a,b)   #7
    ayb = xand(a,b)   #4

    C = 0
    for i in range(1,8):
        C = ((xand(C,axb))|ayb)<<1    #(1+1+4)x7=6x7=42

    return xxor(axb,xand(C,255))    #7 + 4 = 11
    #total: 7+4+42+11 = 64

Bir dalgalanma toplayıcısının denklemidir. C taşımadır. Her seferinde bir bit hesaplanır: her yinelemede taşıma sola yayılır. @Orby tarafından belirtildiği gibi, orijinal sürüm modüler bir ekleme yapmadı. İlk sabitleme her zaman sıfır olduğu için düzelttim ve yinelemede bir döngü kaydettim.


3
Güzel iş, ancak kodunuz düzgün bir şekilde sarılmıyor (yani s(255,2), 257yerine döndürür 1). return ~(~xxor(axb,C)|256) 3 puan ekleyen son satırınızı değiştirerek bunu düzeltebilirsiniz .
Orby

2

C ++ - puan: 113

#define ands(x, y) ~(~x | ~y) << 1
#define xorm(x, y) ~(y | ~(x | y)) | ~(x | ~(x | y))

int add(int x, int y)
{
int x1 = xorm(x, y);
int y1 = ands(x, y);

int x2 = xorm(x1, y1);
int y2 = ands(x1, y1);

int x3 = xorm(x2, y2);
int y3 = ands(x2, y2);

int x4 = xorm(x3, y3);
int y4 = ands(x3, y3);

int x5 = xorm(x4, y4);
int y5 = ands(x4, y4);

int x6 = xorm(x5, y5);
int y6 = ands(x5, y5);

int x7 = xorm(x6, y6);
int y7 = ands(x6, y6);

int x8 = xorm(x7, y7);
int y8 = ands(x7, y7);

return (x8 | y8) % 256;
}

add(1, 255)benim için 128 geri dönüyor, @Ryan.
Orby

@Ve şimdi düzeltildi
rdans

%İzin verilen operatörlerin, yani listesinde değildir ~, |, >>, ve <<. Belki yerine ands(x8|y8, 255)>>1?
Orby

Aslında, ~(~x8 | y8 | 0xFFFFFF00)sadece 4+ puan için hile güzel yapardı.
Orby

2
Ancak, tür byteyerine intotomatik olarak taşması olmaz mı?
gururlu haskeller
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.