In today’s Programming Praxis exercise we have to implement two ways of calculating sines. Let’s get started.
A quick import:
import Data.Fixed
The only real trick we use for the Taylor sine function is to not calculate the factorial for each number, but to keep reusing the previous result so that each new entry only requires two multiplications instead of n.
taylorSin :: Double -> Double
taylorSin x = sum . useful $ zipWith (/)
(map (\k -> (mod' x (2*pi)) ** (2*k + 1) * (-1) ** k) [0..])
(scanl (\a k -> a * k * (k - 1)) 1 [3,5..]) where
useful ~(a:b:c) = a : if abs (a-b) > 1e-7 then useful (b:c) else []
For the recursive solution we use the fact that lim(x -> 0) sin x = x
recSin :: Double -> Double
recSin = f . flip mod' (2 * pi) where
f x = if abs x < 1e-7 then x else
let s = f (x / 3) in 3 * s - 4 * s**3
A quick test shows that everything is working correctly.
main = do mapM_ (print . taylorSin) [1, pi / 2, 10]
mapM_ (print . recSin) [1, pi / 2, 10]
Tags: bonsai, code, Haskell, kata, praxis, programming, recursive, sine, taylor