我一直在努力解决我在书中发现的这个问题,但我无法理解它在脑海中。问题要求我使用series(N, Total)
进行此程序;
1 + 1/2 + 1/3 + 1/4 + ... + 1 /(N-1)。任何帮助让我明白这个问题将不胜感激!非常感谢!
答案 0 :(得分:2)
我不明白你遇到了什么问题。
解决此问题的一种简单方法是定义递归谓词。
这将从1/1到1 /(B-1)总和:
series(B, B, 0).
series(A, B, Total) :-
A < B,
succ(A, A1),
series(A1, B, Total1),
Total is rdiv(1, A) + Total1.
如何阅读:
is/2
需要将所有参数都接地。示例:我们使用它计算总和1 / i为i = 1,...,3 = 1/1 + 1/2 + 1/3 = 11/6:
?- series(1,4,X).
X = 11 rdiv 6 .
答案 1 :(得分:1)
使用meta-predicate foldl/4
可以模仿到目前为止提供的答案。
与@mescalinum did in previous answer一样,我不会使用浮点数,而是arbitrary-precision rational numbers。 与浮点数不同,有理数的加法是可交换和关联的。因此,在总结有理数时,任何添加顺序都会得到相同的结果。
我建议将lambdas与两个元谓词init1/3
和reduce/3
一起使用,如下所示:
seriesR(N,Val) :-
init1(\I^E^(E is rdiv(1,I)),N-1,Rs),
reduce(\X^Y^XY^(XY is X+Y),Rs,Val).
示例查询:
?- seriesR(4,Val).
Val = 11 rdiv 6.
要表明reduce/3
可以帮助加快总结 - 即使它有一些内部开销 - 让我们运行seriesR/2
和{{1}某些 BIG series/3
:
?- time((series(10000,_),false)). % 40,001 inferences, 2.805 CPU in 2.804 seconds (100% CPU, 14259 Lips) false. ?- time((seriesR(10000,_),false)). % 180,019 inferences, 0.060 CPU in 0.060 seconds (100% CPU, 3014245 Lips) false.
让我们深入挖掘一下!
我们使用的implementation lambda expressions会产生可衡量的效果成本。一旦进行适当的优化,这些成本将来可能会消失。
目前,让我们量化这些成本......
N
我们得到num_num_sum(X,Y,Sum) :-
Sum is X+Y.
r_reciprocal(X,Y) :-
Y is rdiv(1,X).
seriesR2(N,Val) :-
init1(r_reciprocal,N-1,Rs),
reduce(num_num_sum,Rs,Val).
和seriesR/2
,我们得到:
seriesR2/2
在这个例子中,使用lambda表达式会产生大约3倍的最坏情况开销。重要的是?也许......但是比使用?- time((between(1,10000,_),seriesR(10,V),false)).
% 1,750,001 inferences, 0.389 CPU in 0.389 seconds (100% CPU, 4500790 Lips)
false.
?- time((between(1,10000,_),seriesR2(10,V),false)).
% 820,001 inferences, 0.137 CPU in 0.137 seconds (100% CPU, 5999216 Lips)
false.
代替foldl
少了几个数量级!
答案 2 :(得分:0)
据我了解,你需要一个评估这个函数的谓词:
在过程语言中,你会写出类似迭代解决方案的东西:
static double iterative_harmonic_number( int n )
{
if ( n < 1 ) throw new ArgumentOutOfRangeException("n");
double r = 0.0 ;
while ( n > 0 )
{
r += 1.0 / n-- ;
}
return r ;
}
或者这个递归解决方案:
static double recursive_harmonic_number( int n )
{
if ( n < 1 ) throw new ArgumentOutOfRangeException("n");
double h = (1.0 / n) ;
if ( n > 1 ) { h += recursive_harmonic_number(n-1) ; } ;
return h ;
}
两者在1..10中产生相同的结果:
iterative recursive
--------------- ---
f( 1 ): 1 1
f( 2 ): 1.5 1.5
f( 3 ): 1.83333333333333 1.83333333333333
f( 4 ): 2.08333333333333 2.08333333333333
f( 5 ): 2.28333333333333 2.28333333333333
f( 6 ): 2.45 2.45
f( 7 ): 2.59285714285714 2.59285714285714
f( 8 ): 2.71785714285714 2.71785714285714
f( 9 ): 2.82896825396825 2.82896825396825
f( 10 ): 2.92896825396825 2.92896825396825
Prolog非常适合递归解决方案,所以让我们来看看。
我们可以在Prolog中直接表达:
f( 1 , 1.0 ) . % the terminating special case
f( N , R ) :- % the general case:
N > 1 , % - N must be positive (and greater than 1),
N1 is N-1 , % - compute N-1
f(N1,T) , % - recursively evaluate it
R is T + 1.0 / N % - add that result to the current N's reciprocal
. % Easy!