我有一些代码应该通过泰勒级数定义找到 sin(15°)
的近似值,并将其与内置函数sin
进行比较。
我有不同的结果。
X
-弧度值R
-系列和的当前值Eps
-准确性值S
-签名F
-N
的阶乘值XN
-X
的值乘以N
的幂N
-功率1,3,5 ... % base
sin_taylor(_,R,Eps,S,FN,XN,_) :-
abs(S*XN/FN) < Eps,
R = 0, !.
% step
sin_taylor(X, R, Eps, S, FN, XN, N) :-
S1 = S*(-1),
N1 = N+1,
FN1 = FN*(2*N+2)*(2*N+3),
XN1 = XN*X*X,
sin_taylor(X,R1,Eps,S1,FN1,XN1,N1),
R is R1+S*XN/FN.
% auxiliary predicate to supply parameters to the main one
sin(X,R,Eps) :-
sin_taylor(X,R1,Eps,-1,1,X*X,1),
R is 1+R1.
控制台中的结果
?- X is 15*(pi / 180), sin(X,R,0.0001).
X = 0.2617993877991494,
R = 0.931695959721973.
?- X is 15*(pi / 180), R0 is sin(X).
X = 0.2617993877991494,
R0 = 0.25881904510252074.
答案 0 :(得分:2)
无法在您的代码中识别正确的n项...阶乘计算隐藏在哪里?请记住,早期的优化是软件工程中所有弊端的根源:)
Wikipedia中列出的解决方案的直接翻译使我想到了这段代码(嗯,应该在谓词名称中引用Maclaurin 和 Taylor ...)
class C extends ReactComponent {
constructor() {
var handleMerging = handleMerging.bind(this);
handleMerging().then(...);
}
}
给出合理的结果:
:- module(sin_taylor,
[sin/3
,rad_deg/2
,fact/2
]).
% help predicate to give parameters to the main one
sin(X,R,Eps):-
syn_taylor(X,Eps,0,R).
syn_taylor(X,Eps,N,R) :-
S is -1**N,
T is 2*N+1,
fact(T,D),
E is X**T,
Q is S*E/D,
( Q < Eps
-> R = Q
; M is N+1,
syn_taylor(X,Eps,M,R1),
R is Q+R1
).
rad_deg(R,D) :-
var(R) -> R is D*(pi / 180).
% tbd compute D from R
fact(N,F) :- N>0 -> N1 is N-1, fact(N1,F1), F is N*F1 ; F=1.
答案 1 :(得分:2)
如果从最小的求和数开始,然后使用霍纳模式,则可获得更好的结果,并且数值误差更少。但是问题是,如何找出哪个索引MainWindow
应该给您最小的求和数k
?
对于ak
,被乘数为sin/1
。
对于an = (-1)n * x(2*n+1) / (2n+1)!
,其中x = u * 10(-v)
是u
的尾数,而x
是v
的负指数,我们看到:
x
因此,如果我们想要|an| < |x(2*n+1)| = 10((log10(|u|) - v) * (2*n+1))
位数字,我们可以尝试以最小的方式增加索引
p
如果我们已经有k = ceiling(p / (2 * (log10(|u|) - v)))
的问题,这将是最好的选择。最小的求和索引|x| =< 1/2
在这里计算:
k
谓词mp_sin(X, P, Y) :-
K is integer(ceiling(requested(P)/(2*dec_log10(X)))),
init_sin(K, X, P, U),
mp_sin(U, X, P, Y).
和init_sin/4
然后从最小的被加数到最大的被加数mp_sin/4
向后计算正弦值,并使用Horner模式同时获得和:>
a0
内部谓词mp_sin((0, S), _, _, S) :- !.
mp_sin(U, X, P, Y) :-
next_sin(U, X, P, V),
mp_sin(V, X, P, Y).
init_sin(K, X, P, (K, S)) :-
(K mod 2 =:= 0 -> V = X; V = -X),
mp_math(V/(2*K+1), P, S).
next_sin((L, T), X, P, (K, S)) :-
K is L-1,
(K mod 2 =:= 0 -> V = X; V = -X),
mp_math((T*X*X/(2*K+2)+V)/(2*K+1), P, S).
在这里用于BigDecimal算术,因此我们还可以以mp_math/3
的精度来计算sin/1
,这对于常规浮点数是不可能的。结果如下:
p = 100
由于所有computations均以给定的精度完成,因此当您使用Horner模式进行向后计算时,只需要很少的位。更少的数字错误意味着您可以使用更少的位来驱动计算。但是,您仍然需要一点额外的精度。
要获得Jekejeke Prolog 4, Runtime Library 1.4.1 (20 August 2019)
?- use_module(library(decimal/multi)).
% 7 consults and 0 unloads in 222 ms.
Yes
?- X is mp(15*(pi/180),5), R is mp(sin(X),5).
X = 0d0.26181,
R = 0d0.25883
?- X is mp(15*(pi/180),102), R is mp(sin(X),102).
X = 0d0.2617993877991494365385536152
732919070164307832812588184145787160
256513671905174165523362354451764223
32,
R = 0d0.2588190451025207623488988376
240483283490689013199305138140032073
150569747488019969223679746942496655
21
的结果,我正在使用p = 4
,并且得到了p = 5
的结果,我正在使用p = 100
。尚未有时间找到这种额外精度的启发式方法,并使它对最终用户透明。通常,我们可以使用较小的p = 102
,因此仍在进行中。