Triển khai bộ cộng 8 bit


12

Các thách thức

Thực hiện một hàm chấp nhận hai số nguyên có giá trị nằm trong khoảng từ 0 - 255 và trả về tổng của các số nguyên đó mod 256. Bạn chỉ có thể sử dụng phủ định bitwise (~), bitwise hoặc (|), toán tử dịch chuyển bit (>>, <<) và gán (=).

Những thứ bạn không thể sử dụng bao gồm (nhưng không giới hạn)

  • Phép cộng, phép trừ, phép nhân và phép chia
  • Vòng lặp
  • Câu điều kiện
  • Chức năng gọi

Ít sử dụng nhất của nhị phân hoặc, phủ định nhị phân và các hoạt động dịch chuyển bit sẽ thắng . Trong trường hợp hòa, giải pháp phổ biến nhất sẽ thắng. Như mọi khi, sơ hở tiêu chuẩn áp dụng.

Dưới đây là một ví dụ về bộ cộng 2 bit đơn giản. Nó sử dụng 77 phủ định nhị phân, 28 ors nhị phân và 2 bit bit cho tổng số 107 (có thể thấy điều này bằng cách chạy bộ tiền xử lý C với gcc -E). Nó có thể được thực hiện hiệu quả hơn nhiều bằng cách loại bỏ các #defines và đơn giản hóa các biểu thức kết quả, nhưng tôi đã để chúng rõ ràng.

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

Cập nhật: Đã thêm ví dụ và thay đổi phê bình chấm điểm


2
Tại sao không bitwise "và"?
rdans

@Ryan Hầu hết mọi người quen thuộc với cổng NAND hơn cổng NOR :)
Orby

1
đệ quy được tính là một vòng lặp?
rdans

@Ryan Recursion được tính là một vòng lặp, mặc dù tôi không chắc cách bạn thực hiện nó mà không có một tuyên bố có điều kiện.
Orby

Là tràn được xác định hoặc tôi chỉ có thể xuất bất cứ điều gì nếu nó tràn?
Comitern

Câu trả lời:


8

Python, 36 thao tác

Một phương thức logarit trong tham số "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

Ý tưởng là để tìm ra các chỉ số tràn và nguyên nhân mang. Ban đầu, đây chỉ là nơi cả aandd bcó a 1. Nhưng vì các bit mang có thể gây ra sự chồng chéo hơn nữa, điều này cần phải được xác định lặp đi lặp lại.

Thay vì tràn từng chỉ số vào một chỉ số tiếp theo, chúng tôi tăng tốc quá trình bằng cách di chuyển 1 chỉ mục, sau đó 2 chỉ số, sau đó 4 chỉ số, chắc chắn nhớ những nơi xảy ra tràn (H) và khi tràn không thể xảy ra nữa (K ).


Một giải pháp lặp đơn giản hơn với 47 thao tác:

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

Kiểm tra giàn khoan, cho bất cứ ai muốn sao chép nó.

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

8

C - 0

Nó sử dụng các toán tử bên ngoài ~, |, >>, <<, và =, nhưng tôi thấy các giải pháp sử dụng toán tử đúc và dấu phẩy, vì vậy tôi đoán quy tắc không quá nghiêm ngặt với điều kiện là nó không sử dụng các toán tử bị cấm.

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

Đây rõ ràng là một lỗ hổng, nhưng +1 để chỉ ra nó.
Orby

7

trăn, điểm = 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)

Bỏ vòng lặp. Đó là 10 op mỗi vòng lặp 7 vòng, 7 cho xor cuối cùng và 3 để nén bit thứ 9 ở cuối.

Thực hiện phương trình x+y = x^y + 2*(x&y)bằng cách lặp lại 8 lần. Mỗi lần có thêm một bit 0 ở dưới cùng y.


7

C, Điểm: 77 60

Chơi gôn chỉ vì địa ngục của nó, 206 169 131 byte:

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

Mở rộng:

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

Về cơ bản, cùng một giải pháp (về mặt toán học) mà @KeithRandall @JuanICarrano đã đưa ra, nhưng tận dụng khả năng của C để chơi nhanh và lỏng với các loại biến và con trỏ để xóa sạch mọi thứ sau 8 bit đầu tiên mà không cần sử dụng thêm toán tử nào nữa.

Phụ thuộc vào tính chất cuối của máy và sizeof () một int và char, nhưng có thể được chuyển đến hầu hết các ứng dụng cụ thể của máy với toán học con trỏ thích hợp.

EDIT: Đây là một thách thức mà C (hoặc các ngôn ngữ cấp thấp khác) sẽ có ưu thế riêng biệt - trừ khi có ai đó đưa ra một thuật toán không phải thực hiện.


Nếu bạn sẽ xử lý việc bọc xung quanh theo cách đó, bạn có thể chỉ cần thực hiện unsigned char. Nó sạch hơn và dễ mang theo hơn.
Orby

@Orby - Tôi đoán việc gõ ra unsignedkhông tự nhiên đến với tôi trong môn đánh gôn. Tất nhiên, bạn đúng - cập nhật.
Comitern

4

Python - Điểm 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

Đây là phương trình cho một bộ cộng gợn. C là mang. Nó được tính toán một bit tại một thời điểm: trong mỗi lần lặp lại, carry được truyền sang trái. Như được chỉ ra bởi @Orby, phiên bản gốc không thực hiện bổ sung mô-đun. Tôi đã sửa nó và cũng lưu một chu kỳ trong vòng lặp, vì lần mang đầu tiên luôn bằng không.


3
Công việc tốt, nhưng mã của bạn không bao bọc đúng cách (nghĩa là s(255,2)trả về 257chứ không phải 1). Bạn có thể sửa điều này bằng cách thay đổi dòng cuối cùng của bạn để return ~(~xxor(axb,C)|256) thêm 3 điểm.
Orby

2

C ++ - điểm: 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)đang trả lại 128 cho tôi, @Ryan.
Orby

@Orby cố định của nó bây giờ
rdans

%không nằm trong danh sách các nhà khai thác cho phép, cụ thể là ~, |, >>, và <<. Có thể thay thế nó bằng ands(x8|y8, 255)>>1?
Orby

Trên thực tế, ~(~x8 | y8 | 0xFFFFFF00)sẽ thực hiện thủ thuật độc đáo chỉ với hơn 4 điểm số của bạn.
Orby

2
Nhưng sẽ không làm cho loại bytethay vì intsẽ làm cho nó tự động tràn?
tự hào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.