请帮助我,以下内容:
我正在编写一个Prolog程序,它接受两个数字 数字然后将它们组合成一个数字,例如:
Num1: 5
Num2: 1
然后新号码是51。
假设V1
是第一个数字 数字而V2
是第二个数字 数字< / b>。我想将V1
和V2
合并,然后将新数字与V3
相乘,那么我的问题是我该怎么做?
calculateR(R, E, V1, V2, V3, V4):-
R is V1 V2 * V3,
E is R * V4.
感谢您的帮助。
答案 0 :(得分:4)
这是一个直接的解决方案,适用于任何接近ISO的Prolog:
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 :(得分:4)
这是一个更好地阐明Prolog关系性质的版本 - 使用许多Prolog系统(SICStus,SWI,B,GNU,YAP)中提供的library(clpfd)
。它基本上与(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.
唉,嘎嘎嘎嘎。这个答案包含许多必须保持的额外方程式。 Prolog基本上说:哦,是的,有一个解决方案,只要所有这些精美的印刷品都是真的。自己做数学吧!
但让我们面对现实:如果Prolog提供的答案比Yes
所说的要好,那就更好了。
幸运的是,有一些方法可以消除这些额外的条件。其中一个最简单的称为“标签”,其中Prolog将在值之后“试用”值:
?- 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 :(得分: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]).
答案 3 :(得分:3)
编辑:在评论中,@ false指出此答案是特定于SWI-Prolog的。
您可以通过将数字视为原子并将它们连接起来,然后将得到的原子转换为数字来实现您期望的目标。
我将atom_concat/3
用来组合这两个数字。在这个谓词中,第三个参数是第一个和第二个参数中的原子组合。如,
?- atom_concat(blingo, dingo, X).
X = blingodingo.
请注意,当您使用两个数字执行此操作时,结果是 atom 而不是数字。这由包含结果的单引号表示:
?- 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位于10s位置而1位于1s位置,那么5和1的组合将是5 * 10 + 1 * 1
。我在这里建议的答案将使用多位数字,例如calculateR(12, 345, 3, Result)
,Result is 1234 * 3
。取决于您之后的情况可能会或可能不是您想要的结果。
答案 4 :(得分: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.
(代码示例主要是为了实现这个想法。请注意,我在这里使用了来自SWI-Prolog的aggregate_all/3
。通过专门使用ISO谓词可以实现相同的目标。)