我需要编写一个 Haskell 函数,通过传递一个函数、它的导数和初始点 (x0) 作为参数来解析 Newton-Raphson 算法,并返回函数根的近似值。
例子:
f(x) = x^2 − 2x + 1
f′(x) = 3x^2 − 2
x0 = −1.5
.
x3 = −1.618 = x2 − f′(x2)/f(x2)
非常感谢您的所有帮助和建议。
我之前试过的是这样的:
newtonR f g x0 =
if (x0 - (f x0 / g x0)) /= 0 then
newtonR f g (x0 - f x0 / g x0)
else
x0
... 并返回以下错误消息:
No instance for (Show (Double -\> Double))
arising from a use of \`print'
(maybe you haven't applied a function to enough arguments?)
可以从编写一个执行牛顿-拉夫森单次迭代的函数开始。请注意,在函数体之前提供显式类型签名是一种很好且常见的做法:
nrIter :: (Double -> Double) -> (Double -> Double) -> Double -> Double
nrIter f f' x0 = x0 - (f x0 / f' x0)
Haskell 的一个特点是
f'
是一个有效的标识符,这与经典的命令式语言不同。
如评论中所述,由于不可避免的舍入错误,测试浮点数是否相等很容易出错。相反,我们可以提供一个明确的公差级别,并像这样为 Newton-Raphson 编写上层逻辑:
newtonR :: (Double -> Double) -> (Double -> Double) -> Double -> Double -> Double
newtonR f f' tol x0 =
let
x1 = nrIter f f' x0
dx = abs (x1 -x0)
in
if (dx < tol) then x1
else newtonR f f' tol x1
示例测试代码:
我们可以这样计算 2 的立方根的近似值:
main :: IO ()
main = do
let cr2 = newtonR (\x -> x^3 - 2.0) (\x -> 3.0*x^2) 1.0e-9 1.0
putStrLn $ "Cubic root of 2 is close to: " ++ (show cr2)