在prolog中结合两个数字

时间:2014-04-20 12:30:34

标签: prolog

请帮助我,以下内容:

我正在编写一个Prolog程序,它接受两个数字 数字然后将它们组合成一个数字,例如:

Num1: 5
Num2: 1

然后新号码是51。

假设V1是第一个数字 数字V2是第二个数字 数字< / b>。我想将V1V2合并,然后将新数字与V3相乘,那么我的问题是我该怎么做?

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

感谢您的帮助。

5 个答案:

答案 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谓词可以实现相同的目标。)