2014-04-20 31 views
3

請結合兩個數字,你能不能幫我在下面:在序言

我寫一個Prolog程序,它有兩個數字然後將它們合併爲一個號碼,例如:

Num1: 5 
Num2: 1 

然後將新數是51.

假設V1是第一數字V2是第二個數字數字。我想結合V1V2,然後將新號碼與V3相乘,所以我的問題是我該怎麼做?

calculateR(R, E, V1, V2, V3, V4):- 
    R is V1 V2 * V3, 
    E is R * V4. 

您的幫助表示讚賞。

回答

3

編輯: @false在評論中指出,這個答案是SWI-Prolog特有的。

您可以通過將數字視爲原子並連接它們,然後將結果原子轉換爲數字來實現您的期望目標。我想用atom_concat/3來組合這兩個數字。在這個謂詞中,第三個參數是第一個和第二個參數中原子的組合。例如,

?- atom_concat(blingo, dingo, X). 
X = blingodingo. 

需要注意的是,當你這樣做有兩個數字,結果是一個原子不是一個數字。這是由單引號包圍結果表明:

?- atom_concat(5, 1, X). 
X = '51'. 

51 \= '51',我們不能用數字乘以一個原子。我們可以使用atom_number/2這個原子轉換成一個數字:

?- atom_number('51', X). 
X = 51. 

這一切就是這麼簡單!你的謂語可能是這樣的:

calculateR(No1, No2, Multiplier, Result) :- 
    atom_concat(No1, No2, NewNoAtom), 
    atom_number(NewNoAtom, NewNo), 
    Result is NewNo * Multiplier. 

用例:

?- calculateR(5, 1, 3, X). 
X = 153. 

當然,你需要更多,如果你想提示用戶進行輸入。

我期待@Wouter Beek的答案更有效率,因爲它不依賴於將數字轉換爲原子和從原子轉換數字,而是使用假設每個數字都是一個數字來確定基於其位置的結果數字。例如,如果5位於10位,1位位於1位,那麼5和1的組合將是5 * 10 + 1 * 1。我在這裏建議的答案將使用多個數字數字,例如calculateR(12, 345, 3, Result),Result is 1234 * 3。取決於你在做什麼之後可能會或可能不會得到期望的結果。

+2

您正在使用SWI特有的行爲:'atom_concat(5,1,X)'在ISO中產生'type_error(atom,5)'或'type_error(atom,1)' - GNU,SICStus,B,IF,Prolog IV ... – false

+0

謝謝,我感謝你的幫助。它爲我工作,這是最簡單的方法。 – Programer14

2

如果您知道所涉及的數字的基數(且所有數字的基數相同),那麼您可以使用各個數字的反向索引來計算它們的位置總和。使用

:- use_module(library(aggregate)). 
:- use_module(library(lists)). 

digits_to_number(Numbers1, Radix, PositionalSummation):- 
    reverse(Numbers1, Numbers2), 
    aggregate_all(
    sum(PartOfNumber), 
    (
     nth0(Position, Numbers2, Number), 
     PartOfNumber is Number * Radix^Position 
    ), 
    PositionalSummation 
). 

例子:。

?- digits_to_number([5,1], 10, N). 
N = 51. 
?- digits_to_number([5,1], 16, N). 
N = 81. 

(代碼示例主要是爲了跨越帶來的想法請注意,我用aggregate_all/3從SWI-Prolog的在這裏同樣可以使用ISO實現專門謂詞)

+2

謝謝你的努力,但實際上它是太複雜了,因爲我是新來的Prolog,是有一個更簡單的方法? – Programer14

+1

'(**)/ 2'應該用'(^)/ 2'代替,以使其在符合ISO的系統*和* SWI中運行。 – false

+0

@false感謝您指出這一點。我們的確需要'^/2'來處理整數,而'**/2'則需要浮點數。 –

4

這裏是一個直接的解決方案,應該在任何Prolog的工作接近ISO:

digits_radix_to_number(Ds, R, N) :- 
    digits_radix_to_number(Ds, R, 0,N). 

digits_radix_to_number([], _, N,N). 
digits_radix_to_number([D|Ds], R, N0,N) :- 
    N1 is D+N0*R, 
    digits_radix_to_number(Ds, R, N1,N). 

| ?- digits_radix_to_number([1,4,2],10,R). 
R = 142. 
+1

謝謝,我感謝你的幫助。 – Programer14

4

這是一個更好地闡明Prolog的關係性質的版本 - 使用library(clpfd),它在許多Prolog系統(SICStus,SWI,B,GNU,YAP)中都可用。它在本質上是相同的程序作爲一個與(is)/2除了我加入進一步冗餘約束允許系統,以保證在更一般的情況下終止,太:

 
:- use_module(library(clpfd)). 

digits_radix_number(Ds, R, N) :- 
    digits_radix_numberd(Ds, R, 0,N). 

digits_radix_numberd([], _, N,N). 
digits_radix_numberd([D|Ds], R, N0,N) :- 
     D #>= 0, D #< R, 
     R #> 0, 
     N0 #=< N, 
    N1 #= D+N0*R, 
    digits_radix_numberd(Ds, R, N1,N). 

這裏有一些用途:

?- digits_radix_number([1,4,2],10,N). 
N = 142. 

?- digits_radix_number([1,4,2],R,142). 
R = 10. 

?- digits_radix_number([1,4,2],R,N). 
R in 5..sup, 
    4+R#=_G4515, 
    _G4515*R#=_G4527, 
    _G4515 in 9..sup, 
    N#>=_G4515, 
N in 47..sup, 
    2+_G4527#=N, 
    _G4527 in 45..sup. 

最後一個查詢要求代表[1,4,2]作爲數字的所有可能的基數。正如你所看到的,沒有任何東西可以這樣表現。基數必須是5或更大,考慮到數字4並不奇怪,數字本身必須至少爲47.

假設我們想要得到一個介於1450..1500之間的數值,我們需要什麼基數需要這樣做嗎?

?- digits_radix_number([1,4,2],R,N), N in 1450..1500. 
R in 33..40, 
    4+R#=_G1551, 
    _G1551*R#=_G1563, 
    _G1551 in 37..44, 
N in 1450..1500, 
    2+_G1563#=N, 
    _G1563 in 1448..1498. 

Gnah,又是胡言亂語。這個答案包含許多必須保持的額外方程。 Prolog實質上是這樣說的:噢,是的,如果所有這些細節都是真的,就有一個解決方案。自己做數學!

但是讓我們面對現實:這是更好的,如果序言給出了這樣難以吞嚥的答案比如果它會說Yes

幸運的是有辦法來消除這種額外的條件。最簡單的一種被稱爲「貼標籤」,其中序言將「嘗試」值後的值:

?- digits_radix_number([1,4,2],R,N), N in 1450..1500, labeling([], [N]). 
false. 

這就是明確的迴應吧!沒有解決方案。所有這些額外的條件,其中基本假的,就像在你的保單所有印刷精美...

這裏的另一個問題:由於基數和價值,需要什麼樣的數字?

?- digits_radix_number(D,10,142). 
D = [1, 4, 2] ; 
D = [0, 1, 4, 2] ; 
D = [0, 0, 1, 4, 2] ; 
D = [0, 0, 0, 1, 4, 2] ; 
D = [0, 0, 0, 0, 1, 4, 2] ... 

使查詢永遠不能終止,因爲00142是相同數量142就像007座席號碼7

+2

謝謝,我感謝你的幫助。 – Programer14

4

這是基於@aBathologist的想法和另一種解決方案依靠ISO只有謂詞,並且不依賴於SWI的特質修改和擴展。它也不是最有可能的不需要的解決方案,如calculateR('0x1',1,1,17).,也不是calculateR(1.0e+30,0,1,1.0e+300).它也不會創建不必要的臨時原子。

這樣的想法是對的定義限制爲十進制數:

digit_digit_number(D1, D2, N) :- 
    number_chars(D1, [Ch1]), 
    number_chars(D2, [Ch2]), 
    number_chars(N, [Ch1,Ch2]).