{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} module Math.Root.Finder.FalsePosition ( FalsePosition, falsePosition ) where import Math.Root.Finder -- | @falsePosition f x1 x2 xacc@: Using the false-position method, return a -- root of a function known to lie between x1 and x2. The root is refined -- until its accuracy is += xacc. falsePosition :: (Ord a, Fractional a) => (a -> a) -> a -> a -> a -> Either (FalsePosition a a) a falsePosition f x1 x2 xacc = fmap estimateRoot (findRoot f x1 x2 xacc) -- |Iteratively refine a bracketing interval [x1, x2] of a root of f -- until total convergence (which may or may not ever be achieved) using -- the false-position method. data FalsePosition a b = FalsePosition { fpRoot :: !a , fpDX :: !a , _fpXL :: !a , _fpFL :: !a , _fpXH :: !a , _fpFH :: !a } deriving (Eq, Show) instance (Fractional a, Ord a) => RootFinder FalsePosition a a where initRootFinder f x1 x2 -- step once to compute first estimate | f1 <= 0 && f2 >= 0 || f2 <= 0 && f1 >= 0 = stepRootFinder f $ FalsePosition 0 0 x2 f2 x1 f1 | otherwise = error "FalsePosition: given interval does not bracket a root" where f1 = f x1 f2 = f x2 stepRootFinder f (FalsePosition _ _ xl fl xh fh) = case compare fNew 0 of LT -> FalsePosition xNew (xl - xNew) xNew fNew xh fh EQ -> FalsePosition xNew 0 xNew fNew xNew fNew GT -> FalsePosition xNew (xh - xNew) xl fl xNew fNew where dx = xh - xl xNew = xl + dx * fl / (fl - fh) fNew = f xNew estimateRoot = fpRoot estimateError = fpDX