规则在Prolog中指数为负时计算数字的幂?

时间:2011-11-23 10:54:39

标签: prolog exponentiation

我有一个幂函数pow,它会尝试计算B的值E。到目前为止,我处理案件 -
1.指数为0
2.指数非零

pow(B,0,1).
pow(B,E,Result):-   E2 is E - 1,
                    pow(B,E2,Result2),
                    Result is B*Result2.

如何添加电源功能可以处理负指数的另一种情况?

3 个答案:

答案 0 :(得分:4)

首先,应该考虑如何定义0 0 。从形式上讲,它是不确定。它可能是零或者可能是1.正如Wolfram的Mathworld在其article on powers及其article on zero中所说的那样:

0 0 (第零次幂为零)本身未定义。对于这个数量缺乏明确定义的含义来自相互矛盾的事实, a 0 总是1,所以0 0 应该相等1,但0 a 始终为0(对于 a > 0),所以0 a 应该等于0. 0 0 的定义选择通常被定义为不确定的,尽管定义0 0 = 1允许一些公式简单表达( Knuth 1992; Knuth 1997,p.57)。

所以你应该首先选择如何定义0 0 的特殊情况:它是0吗?是1吗?是不确定的?

我选择将其视为未定义。

话虽如此,你可以看一个正指数,如重复乘法所示(例如10 3 是10 * 10 * 10,或1000),你可以看一个负指数作为指示重复划分(例如,10 -3 是(((1/10)/ 10)/ 10),或0.001)。我的倾向,部分是因为我喜欢这种方法的对称性,部分是为了避免切割(因为切割通常是你没有正确定义解决方案的信号),将是这样的:

% -----------------------------
% The external/public predicate
% -----------------------------
pow( 0 , 0 , _ ) :- ! , fail .
pow( X , N , R ) :-
  pow( X , N , 1 , R )
  .

% -----------------------------------
% the tail-recursive worker predicate
% -----------------------------------
pow( _ , 0 , R , R  ).
pow( X , N , T , R  ) :-
  N > 0 ,
  T1 is T * X ,
  N1 is N-1   ,
  pow( X , N1 , T1 , R )
  .
pow( _ , 0 , R , R  ) :-
  N < 0 ,
  T1 is T / X ,
  N1 is N+1   ,
  pow( X , N1 , T1 , R )
  .

正如其他人所指出的那样,另一种方法是将正指数定义为指示重复乘法,将负指数定义为指示正指数的倒数,因此10 3 为10 * 10 * 10或1,000,和10 -3 是1 /(10 3 ),或1 / 1,000或0.001。为了使用这个定义,我再次避免削减并做这样的事情:

% -----------------------------
% the external/public predicate
% -----------------------------
pow( 0 , 0 , _ ) :-  % 0^0 is indeterminate. Is it 1? Is it 0? Could be either.
  ! ,
  fail
  .
pow( X , N , R ) :-
  N > 0 ,
  pow( X , N , 1 , R )
  .
pow( X , N , R ) :-
  N < 0 ,
  N1 = - N ,
  pow( X , N1 , 1 , R1 ) ,
  R is 1 / R1
  .

% -----------------------------------
% The tail-recursive worker predicate
% -----------------------------------
pow( _ , 0 , R , R  ).
pow( X , N , T , R  ) :-
  N > 0 ,
  T1 is T * X ,
  N1 is N-1   ,
  pow( X , N1 , T1 , R )
  .

答案 1 :(得分:2)

首先,你的第二个子句是非尾递归的(你可以阅读主题here)。这意味着最终,在运行它时,你将耗尽调用堆栈内存。 一个好处是使用累加器使其尾递归。您可以按如下方式实现:

% we add an accumulator to poW/3, making it pow/4.
pow(B, E, Result) :- pow(B, E, 1, Result).

% when we hit 0, our accumulator holds B^E so we unify it with result.
pow(_, 0, Accu, Accu) :- !.

% at each step, we multiply our accumulator by B
pow(B, E, Accu, Result) :-
    NewE is E - 1,
    NewAccu is Accu * B,
    pow(B, NewE, NewAccu, Result).

然后,您可以通过在其他句子之上添加此子句来简单地处理否定案例(它只是告诉序言负面权力是正面的反面):

pow(B, E, Result) :-
    E < 0,
    PositiveE is - E,
    pow(B, PositiveE, 1, R),
    !,
    Result is 1 / R.

请注意,您可以直接使用代码执行此操作:

pow(B, E, Result) :-
    E < 0,
    PositiveE is - E,
    pow(B, PositiveE, R),
    !,
    Result is 1 / R.

另外,我们现在引入了一个非常红的切口(如果需要,请参阅here了解红切的含义)。因此,最好通过这种修改变成绿色切割:

pow(B, E, Result) :-
    E < 0,
    PositiveE is - E,
    pow(B, PositiveE, 1, R),
    !,
    Result is 1 / R.

% we add an accumulator to poW/3, making it pow/4.
pow(B, E, Result) :-
    E >= 0, %************* HERE *****************
    pow(B, E, 1, Result).

% when we hit 0, our accumulator holds B^E so we unify it with result.
pow(_, 0, Accu, Accu) :- !.

% at each step, we multiply our accumulator by B
pow(B, E, Accu, Result) :-
    NewE is E - 1,
    NewAccu is Accu * B,
    pow(B, NewE, NewAccu, Result).

答案 2 :(得分:2)

别忘了a^(2b) = (a^b)^2x^2 = x*x。可以使用累加器以非尾部方式从顶级&#34; UI&#34;中调用尾递归工作谓词。谓语。这样你就不必为负面的权力实现工作谓词,而是重用一个用于正面的权力,并改变它在顶级谓词中的结果(我看到这已被提出):

pow(B, E, R):- E<0 -> ... ; E=:=0 -> ... ; E>0 -> ... .
相关问题