2015-06-15 75 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