我试图弄清楚如何将两个二进制数加在一起,表示为列表。例如: addNumbers([1,0,1],[1,1,0,0],X)。应该返回X = [1,0,0,0,1]。
我们不会大声使用剪切(!)来解决这个问题。所以我知道我必须实现各种加法器。现在我添加了用其所需谓词实现的数字:
addDigits(A,B,X,Y) :- myXor(A,B,X), myAnd(A,B,Y).
myAnd(A,B,R) :- A == 1, B == 1, R is 1.
myAnd(A,B,R) :- A == 0, B == 0, R is 0.
myAnd(A,B,R) :- A == 1, B == 0, R is 0.
myAnd(A,B,R) :- A == 0, B == 1, R is 0.
myOr(A,B,R) :- A == 0, B == 0, R is 0.
myOr(A,B,R) :- A == 0, B == 1, R is 1.
myOr(A,B,R) :- A == 1, B == 0, R is 1.
myor(A,B,R) :- A == 1, B == 1, R is 1.
这正确地返回X作为2个二进制数字的总和,Y作为进位。现在我知道我的加法器需要这个。现在实际实现addDigits是我被困的地方。这是我目前所拥有但不起作用的。注意:提示是LSB的开始,但我目前不这样做。
addNumbers([HA|TA],[HB|TB],X) :- adder(HA,HB,Cin,Sum,Cout,X),
append(Sum, X, X),
addNumbers(TA,TB,X).
adder(X,Y,Cin,Sum,Cout) :- addDigits(X,Y,Sum1,Carry1),
addDigits(Sum1, Cin, Sum, Carry2),
myOr(Carry1, Carry2, Cout).
任何帮助/建议将不胜感激。
干杯
答案 0 :(得分:2)
你走得很好。您的主要问题是了解典型的Prolog递归。
但首先,你的二进制函数:它们是正确的,但它更容易,更可读(无论如何你都错过了这个):
myXor(1,0,1).
myXor(0,1,1).
myXor(1,1,0).
myXor(0,0,0).
在第四种情况下,myOr
中存在拼写错误:您拼写为小写“o”。通过此定义,您的adder
确实可以正常工作!
现在,关于递归:你真的需要从LSB开始,否则你甚至不知道要添加哪些位,因为数字不一定是相同的长度。幸运的是,您可以通过将呼叫包裹在reverse
s:
addNumbers(N1, N2, Sum) :-
reverse(N1, N12),
reverse(N2, N22),
addNumbers(N12, N22, 0, [], Sum0),
reverse(Sum0, Sum).
这是Prolog中非常常见的模式:addNumbers / 3调用addNumbers / 5,递归所需的参数更多。 “0”是初始进位,[]是结果的累加器。 这是addNumbers / 5,您的版本有一些更改:
addNumbers([HA|TA],[HB|TB],Cin,X0,X) :-
adder(HA,HB,Cin,Sum,Cout),
append(X0, [Sum], X1),
addNumbers(TA,TB,Cout,X1,X).
首先,请注意您需要在此处接收Cin作为输入参数!此外,我们将X0作为“累加器”变量,也就是说,每次递归调用它都会变长。最后的调用将产生结果,因此它可以使其成为输出变量。为此,您还需要基本案例:
addNumbers([],B,Cin,X0,X) :- % TODO: Respect Cin
append(X0,B,X).
addNumbers(A,[],Cin,X0,X) :- % TODO: Respect Cin
append(X0,A,X).
看看append的结果不是上面的X1(另一个中间变量),而是X?这是因为它的最终结果,它将与调用堆栈中的相同X统一,这样它就成为整个addNumbers / 5调用的输出!
我离开了它未完成,所以剩下一些(小)工作:基本情况需要考虑Cin ......