8 비트 가산기 구현


12

도전

값의 범위가 0-255 인 두 정수를 허용하고 해당 정수 mod 256의 합을 리턴하는 함수를 구현하십시오. 비트 이동 (~), 비트 또는 (|) 비트 이동 연산자 (>>, <<) 만 사용할 수 있습니다. 및 할당 (=)

사용할 수없는 것에는 다음이 포함되지만 이에 국한되지는 않습니다.

  • 더하기, 빼기, 곱하기 및 나누기
  • 루프
  • 조건문
  • 함수 호출

이진 또는 이진 부정 및 비트 시프트 연산의 사용이 가장 적습니다 . 동점 일 경우 가장 인기있는 솔루션이 승리합니다. 항상 그렇듯이 표준 허점이 적용됩니다.

다음은 간단한 2 비트 가산기의 예입니다. 총 107 점으로 77 개의 이진 부정, 28 개의 이진 or 및 2 개의 비트 시프트를 사용합니다 (이는 C 프리 프로세서를으로 실행하여 볼 수 있음 gcc -E). 을 제거 #define하고 결과 표현식을 단순화하여 훨씬 효율적으로 만들 수 있지만 명확성을 위해 남겨 두었습니다.

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

업데이트 : 예제 추가 및 점수 기준 변경


2
왜 비트 "and"가 아닌가?
rdans

@Ryan 대부분의 사람들은 NOR 게이트보다 NAND 게이트에 더 익숙합니다.
Orby

1
재귀는 루프로 계산됩니까?
rdans

@Ryan Recursion은 루프로 계산되지만 조건문없이 구현하는 방법을 잘 모르겠습니다.
Orby

오버플로가 정의되어 있거나 오버플로가 발생하면 아무것도 출력 할 수 있습니까?
Comintern

답변:


8

Python, 36 회

매개 변수 "8"에 로그인 방법!

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

아이디어는 어느 지수가 오버플로되고 캐리를 유발하는지 파악하는 것입니다. 처음에 이것은 aandd b가 둘 다있는 곳 1입니다. 그러나 캐리 된 비트는 더 많은 오버 로우를 유발할 수 있기 때문에 반복적으로 결정해야합니다.

각 인덱스를 다음 인덱스로 오버플로하지 않고 오버플로가 발생한 위치 (H)와 오버플로가 더 이상 발생할 수없는 위치 (K ).


47 개의 작업이 있는 더 간단한 반복 솔루션 :

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

복사하려는 사람을위한 테스트 리그.

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

~, |, >>, << 및 = 외부의 연산자를 사용하지만 캐스팅 및 쉼표 연산자를 사용하는 솔루션을 볼 수 있으므로 금지 된 연산자를 사용하지 않으면 규칙이 너무 엄격하지 않은 것 같습니다.

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];
}

이것은 분명히 허점이지만 지적하기 위해 +1입니다.
Orby

7

파이썬, 점수 = 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)

루프를 풉니 다. 루프 당 10 ops에 7 루프, 마지막 xor에 7, 마지막에 9 비트를 스쿼시합니다.

방정식 x+y = x^y + 2*(x&y)을 8 회 반복 하여 방정식 을 구현합니다 . 의 맨 아래에 0 비트가 하나 더있을 때마다 y.


7

C, 점수 : 77 60

206 169 131 바이트 : 그것의 지옥을 위해 골프를 쳤다 :

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

넓히는:

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

본질적으로 @KeithRandall @JuanICarrano 와 동일한 솔루션 (수학적으로)이 있지만, 더 많은 연산자를 사용하지 않고 첫 8 비트 이후에 모든 것을 지우는 변수 유형 및 포인터로 C를 빠르고 느슨하게 재생할 수있는 C의 기능을 활용합니다.

기계의 엔디안 (endian-ness)과 int와 char의 sizeof ()에 따라 다르지만, 적절한 포인터 수학으로 대부분의 기계 특정 응용 프로그램으로 이식 될 수 있어야합니다.

편집 : 이것은 누군가가 휴대 할 필요가없는 알고리즘을 제시하지 않는 한 C (또는 다른 저수준 언어)가 뚜렷한 우위를 점할 것입니다.


그런 식으로 랩을 처리하려면로 캐스팅 할 수 있습니다 unsigned char. 더 깨끗하고 휴대가 편리합니다.
Orby

@ Orby- unsigned코드 골프에서 타이핑하는 것이 자연스럽게 이루어지지 않는다고 생각 합니다. 당신은 물론입니다-업데이트되었습니다.
Comintern

4

파이썬 -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

잔물결 가산기의 방정식입니다. C는 캐리입니다. 한 번에 한 비트 씩 계산됩니다. 각 반복마다 캐리가 왼쪽으로 전파됩니다. @Orby가 지적했듯이 원래 버전은 모듈 식 추가를하지 않았습니다. 첫 번째 반입이 항상 0이므로 고정하고 반복주기를 절약했습니다.


3
훌륭하지만 코드가 제대로 감싸지지 않습니다 (예 : 대신 s(255,2)반환 ). 3 점을 추가하는 마지막 줄을 변경하여이를 수정할 수 있습니다 . 2571return ~(~xxor(axb,C)|256)
Orby

2

C ++ 점수 : 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)@Ryan, 128을 반환합니다.
Orby

그 지금 고정 @Orby
rdans

%허용 된 사업자, 즉 목록에없는 ~, |, >>,와 <<. 어쩌면 ands(x8|y8, 255)>>1?
Orby

실제로, ~(~x8 | y8 | 0xFFFFFF00)당신의 점수에 4 +만으로 트릭을 잘 수행 할 것입니다.
Orby

2
그러나 byte대신에 유형 int을 만들지 않으면 자동으로 오버플로가 발생합니까?
자랑스런 Haskeller
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.