如果您从最小的加数开始,然后使用霍纳模式,您将获得更好的结果,更少的数字错误。但问题是,如何确定哪个索引k
应该给你最小的 summand ?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
然后从最小 summand 到最大 summand 反向计算正弦,同时使用 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).
内部谓词mp_math/3
在这里用于 BigDecimal 算术,因此我们也可以sin/1
使用 的精度进行计算p = 100
,这对于通常的浮点数是不可能的。以下是一些结果:
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
由于所有计算都以给定的精度完成,因此当您使用 Horner 模式进行反向计算时,您只需要很少的位。更少的数字错误意味着您可以用更少的位来驱动计算。但是你仍然需要一点额外的精度。
得到p = 4
我正在使用的结果p = 5
,并得到p = 100
我正在使用的结果p = 102
。还没有时间为这种额外的精度找到启发式方法,并使其对最终用户透明。我们通常也可以使用更小的k
,所以这仍在进行中。