【问题标题】:Calculate pi in prolog recursively with Leibniz formula用莱布尼茨公式递归计算prolog中的pi
【发布时间】:2023-12-31 02:15:01
【问题描述】:

我想学习一些序言,并找到了针对给定谓词 pi(10, Result) 递归计算 pi 的练习。我不希望它是尾递归的,因为我发现尾递归更容易。我一直在尝试这样做几个小时,但似乎我无法找到解决方案,这就是我已经走了多远:

(我使用莱布尼茨的圆周率公式作为参考)

pi(0, 0).   
pi(Next, Result) :-
    Num is -1**(Next + 1),
    Part is Num / (2 * Next - 1),
    N1 is Next -1,
    pi(N1, R),
    Result is Part + R.

现在,我知道最后的添加是错误的。另外我需要将最终结果乘以 4,但我不知道该怎么做。如果有人能帮忙,我会很高兴。不,这不是家庭作业或任何东西。 :)

【问题讨论】:

  • 我没有检查您的代码以获得正确的公式(我假设您可以这样做)。但是,您需要在递归子句中进行测试,使其排除基本情况。像Next > 0 和/或Result > 0 之类的东西,或者这种情况的任何要求。此外,由于您正在处理浮点数,因此您无法在基本情况下精确地寻找 0。您将需要使用0.0 周围的间隔(epsilon)来检查。否则,您可能永远无法匹配它。
  • 如果要递归执行一个操作,那么最后乘以4,使用单独的谓词。您的 pi 变为 pi_over_4。然后创建pi(P) :- pi_over_4(..., R), P is R * 4.
  • 仅供参考,Resultant ==> Result.
  • 仅供参考,Prolog 确实允许您使用更复杂的表达式,例如 Part is Num / (2*Next - 1),因此您不需要 SubDenom
  • 我明白了。基本情况的第一个参数匹配,因为它是一个整数,而第二个不匹配但实例化了一个变量,所以是的,这有效。 Num is -1**Exponent 可能只是为了获得该术语的标志而过分杀伤力。您可以只检查该位并执行-> ;(if-else),或者在每次迭代中包含一个交替的 -1/1 乘数参数。

标签: recursion prolog


【解决方案1】:

这里有一个稍微不同的转折,它基于达到给定的精度而终止。它也是尾递归的。因为 Leibniz 收敛速度非常慢,所以当使用简单递归完成时,公式会占用大量堆栈。它不是一个非常适合任何语言的递归解决方案的算法。然而,一个聪明的 Prolog 解释器可以利用尾递归并避免这种情况。仅作为示例,它只允许特定范围内的精度。

pi(Precision, Pi) :-
    Precision > 0.0000001,
    Precision < 0.1,
    pi_over_4(1, 1, Precision/4, 1, Pi_over_4),  % Compensate for *4 later
    Pi is Pi_over_4 * 4.

pi_over_4(AbsDenominator, Numerator, Precision, Sum, Result) :-
    NewAbsDenominator is AbsDenominator + 2,
    NewNumerator is -Numerator,
    NewSum is Sum + NewNumerator/NewAbsDenominator,
    (   abs(NewSum - Sum) < Precision
    ->  Result = NewSum
    ;   pi_over_4(NewAbsDenominator, NewNumerator, Precision, NewSum, Result)
    ).


2 ?- pi(0.0001, P).
P = 3.1416426510898874.

3 ?- pi(0.00001, P).
P = 3.141597653564762.

4 ?- pi(0.000005, P).
P = 3.141595153583494.

这严格来说是对 Prolog 的强制使用,而这并不是 Prolog 的强项。

【讨论】:

    最近更新 更多