+-- | Solve equation using Newton-Raphson method. Root must be

+-- bracketed. If Newton's step jumps outside of bracket or do not

+-- converge sufficiently fast function reverts to bisection.

+solveNewton :: Int -- ^ Maximum number of iterations

+ -> Double -- ^ Absolute error tolerance

+ -> (Double,Double) -- ^ Lower and upper bounds for root

+ -> (Double -> Double) -- ^ Function

+ -> (Double -> Double) -- ^ Function's derivative

+solveNewton nMax eps (lo,hi) f f'

+ | flo * fhi > 0 = NotBracketed

+ | otherwise = let d = 0.5*(hi-lo)

+ fun = worker 0 d mid (f mid) (f' mid)

+ in if flo < 0 then fun lo hi

+ worker i dxOld x fx fx' a b

+ -- Convergence achieved

+ | fx == 0 = Root x -- x is a root

+ | within 1 a b = Root x -- Bracket is too tight. No improvements could be made

+ | abs (a - b) < eps = Root x --

+ | abs dx < eps = Root x' -- Precision achieved

+ | within 0 x x' = Root x' -- Newton step doesn't improve solution

+ | i > nMax = SearchFailed

+ -- Newton step jumped out of range or step decreases too slow.

+ -- Revert to bisection.

+ -- NOTE this guard is selected if dx evaluated to NaN or ±∞.

+ | not ((a - x')*(b - x') < 0) || abs (dxOld / dx) < 2 =

+ let dx' = 0.5 * (b - a)

+ in if fx < 0 then step dx' mid

+ if fx < 0 then step dx x'

+ | fy < 0 = worker (i+1) dy y (f y) (f' y) y b

+ | otherwise = worker (i+1) dy y (f y) (f' y) a y

+{-# INLINABLE solveNewton #-}

-- * Ridders, C.F.J. (1979) A new algorithm for computing a single