2015-06-15 47 views
1

我解决问题(未定期总和!!内部限制)两个列表的求和元件: 清单表示整数说用L 12345 = [12,34,5]的每个元素应当练习是编写一个函数(和),它将两个列表相加并给出它们的和的等价列表,它们表示两个整数的和。的Prolog:表示整数

?-sum([11,11],[11,11],L,0). 
L=[22,22]. 

?-sum([12,81],[11,44],L,0). 
L=[24,25]. 

//digit fxn for making sure that we insert an elemnt of two or single integer 
//and saving the overflow digit in S1. 

我的代码,让我错误:

digit(X,D,S1):- S is X/100,S1 is integer(S),0 is S1,D is X. 

digit(X,D,S1):-D is mod(X/100). 

sum([],[],[],0). 

sum(H1|T1,H|T,H3|T3,S):-Z is H1+H+S ,digit(Z,H3,S1),sum(T1,T,T3,S1). 

回答

0

您的列表适用于所有意图和目的基数为100的数字。解决这个问题的简单方法是以与您长时间评估它相同的方式进行算术:从最低有效数字开始,工作到最高有效数字,累加每对数字,并向左移动如果溢出。

我们扭转名单,以便让我们轻松地从右到左的工作。你会注意到,工作者谓词sum_list_mod_100/4构建的结果是正确的顺序。

sum_list_mod_100(Xs , Ys , Zs) :-  % to compute the sum of a list representing a base-100 integer. 
    reverse(Xs , X1) ,     % - reverse the digits of the left hand side (so we're working from least- to most-significant digit) 
    reverse(Ys , Y1) ,     % - reverse the digits of the right hand side (so we're working from least- to most-significant digit) 
    sum_list_mod_100(X1 , Y1 , 0 , Zs) . % - invoke the worker with the carry initialized as zero. 
    . 

sum_list_mod_100([]  , [] , C , [] ) .   % both lists are empty w/o carry: terminate. 
    C = 0            % 
    .             % 
sum_list_mod_100([]  , [] , C , [C]) :-  % both lists are empty with a carry: prepend the carry to the result. 
    C > 0            % 
    .             % 
sum_list_mod_100([X|Xs] , [] , C , [Z|Zs] ) :- % right-hand side exhausted? 
    sum_digits(X,0,C,Z,C1) ,       % - sum the digits, returning the new digit and the new carry 
    sum_list_mod_100(Xs , [] , C1 , Zs)    % - recurse down, passing the new carry 
    .             % 
sum_list_mod_100([] , [Y|Ys] , C , [Z|Zs] ) :- % left-hand side exhausted? 
    sum_digits(0,Y,C,Z,C1) ,       % - sum the digits, returning the new digit and the new carry 
    sum_list_mod_100([] , Ys , C1 , Zs)    % - recurse down, passing the new carry 
    .             % 
sum_list_mod_100([X|Xs] , [Y|Ys] , C , [Z|Zs]) :- % not yet exhausted? 
    sum_digits(X,Y,C,Z,C1) ,       % - sum the digits, returning the new digit and the new carry 
    sum_list_mod_100(Xs , Ys , C1 , Zs)    % - recurse down passing the new carry 
    .             % Easy! 

sum_digit(X,Y,C,Z,C1) :- % to sum two digits (and the carry) 
    S is X+Y+C ,   % - sum the LHS, RHS and the carry 
    Z is X mod 100 ,  % - compute the digit modulo 100 
    C1 is X div 100   % - compute the carry 
    . 
+0

sum_list_mod_100是arity/3,但尾部是arity/4怎么可能? –

+0

一个普通的序言习语是有一个“public”谓词(在本例中为'sum_list_mod_100/3',它调用一个“私人”工作者谓词,它有一个或两个额外的参数来承载状态。 * functor *(name)作为公共谓词,但具有不同的* arity *(参数数量)。Prolog谓词由functor *和arity独一无二。两个谓词共享一个共同的函子,但由于它们有不同的arities,它们实际上是不同的谓词。 –

0

digit是一个递归谓词。我没有在您的定义中看到递归。

基础案例当然是当位是0,并且该列表是空的:

digit(0, []). 

递归情况下然而在两个,这取决于阉第一个参数分割是变量,或所述第二:

digit(X, [Y|Ys]) :- nonvar(Y), digit(Z, Ys), X is Y + 100 * Z. 
digit(D, [X|Xs]) :- nonvar(D), D>0, X is mod(D,100), R is div(D,100), digit(R, Xs). 

现在你可以使用digit两种方式:

?- digit(12345,X). 
X = [45, 23, 1] ; 
false. 

?- digit(X,[45,23,1]). 
X = 12345. 

注意该名单是颠倒!你可以使它的输出已经颠倒过来(我将把它作为你的锻炼,而我将在这里使用reverse/2;提示:使用accumulators)。

sum(A,B,R) :- reverse(A,AR), reverse(B,BR), 
       digit(A1,AR), digit(B1,BR), 
       R1 is A1+B1, 
       digit(R1,RR), 
       reverse(R,RR). 

?- sum([11,11],[11,11],X). 
X = [22, 22] . 

?- sum([12,81],[11,44],X). 
X = [24, 25] . 
+1

为什么不能用[标签:clpfd]? – repeat

+0

我打算不使用数字函数作为递归函数,它只是为了确保列表的两个头的总和只是单个或两个整数,并且额外的数字S应该加到下一个整数。是的,我错过了名单应该倒过来,因为我应该从右边开始总结,谢谢分配。 –

+1

@repeat,我想使用[clpfd](http://stackoverflow.com/questions/tagged/clpfd)来阅读解决方案,那么为什么不添加一个呢? – fferri

1

平原和简单与

:- use_module(library(clpfd)). 

digitFD(X,Zs) :- 
    digitFD_aux(X,Zs,[],Zs). 

digitFD_aux(X,[_],Zs,[X|Zs]) :- 
    X in 0..99. 
digitFD_aux(X,[_|Ys],Zs0,Zs) :- 
    X #> 99, 
    Z #> 0, 
    Y in 0..99, 
    X #= Y + 100 * Z, 
    digitFD_aux(Z,Ys,[Y|Zs0],Zs). 

让我们来测试一下digitFD/2

?- As = [12,34,56,78], digitFD(N,As). 
As = [12,34,56,78], N = 12345678 ; 
false. 

?- N = 123456789, digitFD(N,As). 
N = 123456789, As = [1,23,45,67,89] ; 
false. 

行!我们来定义sumFD/4

sumFD(As,Bs,Cs,Zs) :- 
    digitFD(A,As), 
    digitFD(B,Bs), 
    C#= A+B, 
    digitFD(C,Cs), 
    append([As,Bs,Cs],Zs). 

让我们来使用它!

?- sumFD([11,11],[11,11],Xs,Zs), labeling([],Zs). 
Xs = [22,22], Zs = [11,11,11,11,22,22] ; 
false. 

?- sumFD([12,81],[11,44],Xs,Zs), labeling([],Zs). 
Xs = [24,25], Zs = [12,81,11,44,24,25] ; 
false. 
+0

这么多';假。' – false