在 python 中实现 8 位加法器
Implementing 8bit adder in python
我在 python 中实现了一个 8 位加法器,如下所示:
from gates import AND, OR, XOR
from utils import number_to_binary, binary_to_number
def EightBitAdder(s1='110101', s2='00010', carry_in=0):
# Limit to 8 bits
s1 = s1[-8:].zfill(8)
s2 = s2[-8:].zfill(8)
s_out = ''
carry_out = None
for i in range(8):
bit_1 = int(s1[8-1-i])
bit_2 = int(s2[8-1-i])
carry_in = carry_out if (carry_out is not None) else carry_in
value_out = XOR(carry_in, XOR(bit_1, bit_2))
carry_out = OR(AND(bit_1, bit_2), AND(bit_1, carry_in), AND(bit_2, carry_in))
s_out = str(int(value_out)) + s_out
print (" %s (%s) \n+ %s (%s) \n= %s (%s) -- Carry %s" % (s1, binary_to_number(s1), s2, binary_to_number(s2), s_out, binary_to_number(s_out), int(carry_in)))
return (s_out, int(carry_out))
对我来说最引人注目的是 "gates" 会延迟计算,所以它不会 return 1/0 除非我调用 int()
,而且似乎有8 位加法器中有大量的门。例如:
我是不是在 carry/value out 评估的某个地方犯了一个错误(或冗余),或者一个基本的 8 位纹波加法器真的有这么多门吗??
如果直接实现,一个全加器确实有那么多门。您是否考虑过使用复合门,例如 8 位基元或使用 half adder?我没有直接经验,但我不认为全加器在实践中是直接用原语实现的,相反他们可能使用这些中间部分。
nand2tetris 的第二章介绍了半加器方法,如果您要将其应用到您的代码中,可以稍微简化一下:
carry_in = carry_out if (carry_out is not None) else carry_in
value_out = XOR(carry_in, XOR(bit_1, bit_2))
carry_out = OR(AND(bit_1, bit_2), AND(bit_1, carry_in), AND(bit_2, carry_in))
可以写成:
carry_in = carry_out if (carry_out is not None) else carry_in
half_sum = XOR(bit_1, bit_2)
half_carry = AND(bit_1, bit_2)
full_sum = XOR(carry_in, half_sum)
full_carry = AND(half_sum, carry_in)
value_out = full_sum
carry_out = OR(half_carry, full_carry)
这会将每次迭代的门数从 6 减少到 5,因此它应该将输出减少 1/6。不过,我仍然建议将它放在一个单独的门中,因为半加器是独立有用的。
在真正的加法器中,门连接成一个图形,其中一个门的输出可以用作其他几个门的输入。
您正在将输出写为表达式,其中门的输出只能在一个地方使用。
这是通过将每个输出的整个表达式复制到所有使用它的地方来实现的。您在每次迭代中执行此操作 - carry_in
用于生成值一次,并使用 3 次生成下一个进位。
进位表达式的大小在每次迭代中乘以 3,导致您使用的运算符数量呈指数级增长。
您可能应该以可以保留门图的不同形式生成输出,例如静态单一赋值:https://en.wikipedia.org/wiki/Static_single_assignment_form
我在 python 中实现了一个 8 位加法器,如下所示:
from gates import AND, OR, XOR
from utils import number_to_binary, binary_to_number
def EightBitAdder(s1='110101', s2='00010', carry_in=0):
# Limit to 8 bits
s1 = s1[-8:].zfill(8)
s2 = s2[-8:].zfill(8)
s_out = ''
carry_out = None
for i in range(8):
bit_1 = int(s1[8-1-i])
bit_2 = int(s2[8-1-i])
carry_in = carry_out if (carry_out is not None) else carry_in
value_out = XOR(carry_in, XOR(bit_1, bit_2))
carry_out = OR(AND(bit_1, bit_2), AND(bit_1, carry_in), AND(bit_2, carry_in))
s_out = str(int(value_out)) + s_out
print (" %s (%s) \n+ %s (%s) \n= %s (%s) -- Carry %s" % (s1, binary_to_number(s1), s2, binary_to_number(s2), s_out, binary_to_number(s_out), int(carry_in)))
return (s_out, int(carry_out))
对我来说最引人注目的是 "gates" 会延迟计算,所以它不会 return 1/0 除非我调用 int()
,而且似乎有8 位加法器中有大量的门。例如:
我是不是在 carry/value out 评估的某个地方犯了一个错误(或冗余),或者一个基本的 8 位纹波加法器真的有这么多门吗??
如果直接实现,一个全加器确实有那么多门。您是否考虑过使用复合门,例如 8 位基元或使用 half adder?我没有直接经验,但我不认为全加器在实践中是直接用原语实现的,相反他们可能使用这些中间部分。
nand2tetris 的第二章介绍了半加器方法,如果您要将其应用到您的代码中,可以稍微简化一下:
carry_in = carry_out if (carry_out is not None) else carry_in
value_out = XOR(carry_in, XOR(bit_1, bit_2))
carry_out = OR(AND(bit_1, bit_2), AND(bit_1, carry_in), AND(bit_2, carry_in))
可以写成:
carry_in = carry_out if (carry_out is not None) else carry_in
half_sum = XOR(bit_1, bit_2)
half_carry = AND(bit_1, bit_2)
full_sum = XOR(carry_in, half_sum)
full_carry = AND(half_sum, carry_in)
value_out = full_sum
carry_out = OR(half_carry, full_carry)
这会将每次迭代的门数从 6 减少到 5,因此它应该将输出减少 1/6。不过,我仍然建议将它放在一个单独的门中,因为半加器是独立有用的。
在真正的加法器中,门连接成一个图形,其中一个门的输出可以用作其他几个门的输入。
您正在将输出写为表达式,其中门的输出只能在一个地方使用。
这是通过将每个输出的整个表达式复制到所有使用它的地方来实现的。您在每次迭代中执行此操作 - carry_in
用于生成值一次,并使用 3 次生成下一个进位。
进位表达式的大小在每次迭代中乘以 3,导致您使用的运算符数量呈指数级增长。
您可能应该以可以保留门图的不同形式生成输出,例如静态单一赋值:https://en.wikipedia.org/wiki/Static_single_assignment_form