Cosinus und Sinus
Sinus und Cosinus eines Winkels können berechnet werden, indem der Winkel zuerst mehrfach halbiert wird, bis er kleiner als eine gewählte Grenze ist, dann für den kleinen Winkel der Tangens anhand der Padé-Approximation
tan(x) = x(1+(x²/105-1)(x/3)²)/(1+(x²/7-4)(x/3)²)
berechnet wird, danach mittels der Folgerung
tan(2x) = 2tan(x)/(1−tan²(x))
des Additionstheorems der Tangens für den ursprünglichen Winkel berechnet wird und man zum Schluss aus dem Tangens den Cosinus
cos(x) = (1-tan²(x))/(1+tan²(x))
und den Sinus
sin(x) = 2tan(x)/(1 + tan²(x))
ermittelt.
Es ergibt sich folgender Code:
(setq cosine-sine
(letrec
#| half za until it is smaller than d |#
((repeated-halving
(lambda (d za k)
(if
(less? za d)
(list za k)
(repeated-halving d (/ za 2) (+ k 1)))))
#| padé approximation of tangent |#
(pade
(lambda (za)
(let
((zaza (* za za)))
(let
((zaza9 (/ zaza 9)))
(* za
(+ 1 (* (- (/ zaza 105) 1) zaza9))
(/ 1 (+ 1 (* (- (/ zaza 7) 4) zaza9))))))))
#| identity for double angle |#
(double-angle-identity
(lambda (ta k)
(if
(less? k 1)
ta
(double-angle-identity
(/ (* 2 ta) (- 1 (* ta ta)))
(- k 1)))))
#| tangent to cosine and sine |#
(tangent-to-cosine-and-sine
(lambda (ta)
(let
((tata (* ta ta)))
(list
(/ (- 1 tata) (+ 1 tata))
(/ (* 2 ta) (+ 1 tata)))))))
#| repeated halving, tangent approximation, then calculate cosine and sine |#
(lambda (z d)
(if
(less? 0 d)
(let
((za-k (repeated-halving d (/ z 2) 0)))
(tangent-to-cosine-and-sine
(double-angle-identity
(pade (first za-k))
(second za-k))))
(throw (quote error) "d must be bigger than 0")))))
Quellen
http://math.stackexchange.com/questions/97560/numerically-efficient-approximation-of-coss
http://fr.wikipedia.org/wiki/Approximant_de_Pad%C3%A9
tan(x) = x(1+(x²/105-1)(x/3)²)/(1+(x²/7-4)(x/3)²)
berechnet wird, danach mittels der Folgerung
tan(2x) = 2tan(x)/(1−tan²(x))
des Additionstheorems der Tangens für den ursprünglichen Winkel berechnet wird und man zum Schluss aus dem Tangens den Cosinus
cos(x) = (1-tan²(x))/(1+tan²(x))
und den Sinus
sin(x) = 2tan(x)/(1 + tan²(x))
ermittelt.
Es ergibt sich folgender Code:
(setq cosine-sine
(letrec
#| half za until it is smaller than d |#
((repeated-halving
(lambda (d za k)
(if
(less? za d)
(list za k)
(repeated-halving d (/ za 2) (+ k 1)))))
#| padé approximation of tangent |#
(pade
(lambda (za)
(let
((zaza (* za za)))
(let
((zaza9 (/ zaza 9)))
(* za
(+ 1 (* (- (/ zaza 105) 1) zaza9))
(/ 1 (+ 1 (* (- (/ zaza 7) 4) zaza9))))))))
#| identity for double angle |#
(double-angle-identity
(lambda (ta k)
(if
(less? k 1)
ta
(double-angle-identity
(/ (* 2 ta) (- 1 (* ta ta)))
(- k 1)))))
#| tangent to cosine and sine |#
(tangent-to-cosine-and-sine
(lambda (ta)
(let
((tata (* ta ta)))
(list
(/ (- 1 tata) (+ 1 tata))
(/ (* 2 ta) (+ 1 tata)))))))
#| repeated halving, tangent approximation, then calculate cosine and sine |#
(lambda (z d)
(if
(less? 0 d)
(let
((za-k (repeated-halving d (/ z 2) 0)))
(tangent-to-cosine-and-sine
(double-angle-identity
(pade (first za-k))
(second za-k))))
(throw (quote error) "d must be bigger than 0")))))
Quellen
http://math.stackexchange.com/questions/97560/numerically-efficient-approximation-of-coss
http://fr.wikipedia.org/wiki/Approximant_de_Pad%C3%A9