实现一个8位加法器


12

挑战

实现一个函数,该函数接受值范围为0-255的两个整数,并返回这些整数的总和256。您只能使用按位取反(〜),按位或(|),移位运算符(>>,<<) ,以及赋值(=)。

您不能使用的东西包括(但不限于)

  • 加,减,乘和除
  • 循环
  • 条件语句
  • 函数调用

最好使用二进制或二进制取反以及移位操作。如果出现平局,则最受欢迎的解决方案将获胜。与往常一样,存在标准漏洞

这是一个简单的2位加法器的示例。它使用77个二进制取反,28个二进制“或”和2个移位,总共得到107分(可以通过运行带有C的预处理器来看到gcc -E)。通过删除#defines并简化结果表达式,可以使其效率更高,但是为了清楚起见,我将其保留了下来。

#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
为什么不按位“与”?
rdans 2014年

@Ryan大多数人比NAND门更熟悉NAND门:)
Orby

1
递归算作一个循环吗?
rdans 2014年

@Ryan Recursion确实算作一个循环,尽管我不确定在没有条件语句的情况下如何实现它。
Orby

是否定义了溢出?如果溢出,我可以输出什么吗?
Comintern

Answers:


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。但是由于进位可能导致进一步的低位,因此需要迭代确定。

不要将每个索引溢出到下一个索引,而是通过移动1个索引,然后是2个索引,然后是4个索引来加快此过程,并确保记住发生溢出的位置(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 2014年

7

python,分数= 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次操作需要7个循环,最后7个异或7次,最后压缩第9位3次。

x+y = x^y + 2*(x&y)通过重复执行8次来实现方程式。每次在的底部再有一个零位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提出的解决方案(数学上)相同,但是利用了C的能力,它可以使用变量类型和指针进行快速和松散的播放,以擦除前8位后的所有内容,而无需使用任何其他运算符。

取决于机器的字节序以及int和char的sizeof(),但是应该能够通过适当的指针数学将其移植到大多数机器特定的应用程序中。

编辑:这是C(或其他低级语言)将拥有明显优势的挑战-除非有人提出不需要携带的算法。


如果您打算以这种方式处理换行,可以将其强制转换为unsigned char。更干净,更便携。
Orby

@Orby-我认为unsigned打代码并不是我自然而然地输入。您当然是对的-已更新。
Comintern

4

Python-得分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指出的那样,原始版本未添加模块化。我修复了该问题,并在迭代中保存了一个周期,因为第一个进位始终为零。


3
做得很好,但是您的代码无法正确环绕(即s(255,2)返回257而不是1)。您可以通过更改最后一行加return ~(~xxor(axb,C)|256) 3点来纠正此问题。
2014年

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)正在为我返回128,@ Ryan。
Orby

@Orby现在已
修复-rdans

%是不允许的运营商,即名单上~|>>,和<<。也许替换为ands(x8|y8, 255)>>1
Orby 2014年

实际上,~(~x8 | y8 | 0xFFFFFF00)只有4分以上的成绩才能达到目标。
2014年

2
但是,不是让类型byte而是使类型int自动溢出吗?
骄傲的haskeller 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.