{-# LANGUAGE NoMonomorphismRestriction #-} {- The Taylor series for the exponential function e^x: e^z = lim n|->inf \Sum_1^inf z^n / n! See: http://en.wikipedia.org/wiki/Power_series See the corresponding C+GMP version for comparison Compile: ghc -O2 -threaded -rtsopts -o power_circ_par power_circ_par.hs Run: ./power_circ_par 4000 10 1 +RTS -N7 -sstderr Measure: time ./power_circ_par 4000 10 1 +RTS -N7 -sstderr 1>/dev/null Parallel version obtained by replacing sum function with parfoldr. -} import System.Environment import Control.Monad import Data.Ratio import Control.Parallel import Control.Parallel.Strategies import Control.DeepSeq import Data.List (foldl') import GHC.Conc (numCapabilities) fact 0 = 1 fact n = n*(fact (n-1)) -- compute e^z up to d digits power_e :: Integer -> Integer -> Integer -> Rational power_e z d v = case v of 1 -> parfoldr (+) 0 (takeWhile (>(1 % (10^d))) taylor) 2 -> parfoldl (+) 0 (takeWhile (>(1 % (10^d))) taylor) 3 -> parfoldl' (+) 0 (takeWhile (>(1 % (10^d))) taylor) _ -> sum (takeWhile (>(1 % (10^d))) taylor) where -- infinite list of entire Taylor series taylor = [ (pow_ints!!n % 1) / (factorials!!n % 1) | n<-[0,1..] ] -- 2 circular lists, to memoise earlier computations factorials = 1:1:[ (toInteger i)*(factorials!!(i-1)) | i<-[2..] ] pow_ints = 1:[ z*(pow_ints!!(i-1)) | i<-[1..] ] -- TODO: change based on numCapabilities chunksize xs = 100 --l `div` sparksPerCapability where l = length xs sparksPerCapability = 2 * numCapabilities chunk n [] = [] chunk n xs = ys : chunk n zs where (ys,zs) = splitAt n xs parfold fold f z [] = z parfold fold f z xs = res where parts = chunk (chunksize xs) xs partsRs = map (fold f z) parts `using` parList rdeepseq res = fold f z partsRs parfoldr = parfold foldr parfoldl = parfold foldl parfoldl' = parfold foldl' main = do args <- getArgs let (z:d:v:_) = map read args :: [Integer] let res = power_e z d v putStrLn $ "e^"++(show z)++" with a precision of "++(show d)++" digits is "++(res `pseq` " omitted") {- putStrLn $ "e^"++(show z)++" with a precision of "++(show d)++" digits is "++(show ((fromRational res)::Double)) putStrLn $ " or as Rational " ++(show res) putStrLn $ "Expected result: " ++(show (exp (fromInteger z))) -}