我正在尝试在Haskell上实现Newton-Raphson方法,到目前为止,我已经设法通过使用iterate
函数使其工作,但是问题是由于性质的缘故,它重新调整了一个无穷大列表函数的功能,所以我想找到一种方法,当在迭代中获得的值落入设定的误差范围内时停止循环,并返回该值
我在这里看了一些博客文章,甚至是一些问题,但是我对Haskell还是相当陌生,并且不完全了解语法,因此对于我来说,阅读代码示例或文档真的很困难。
f(x)和g(x)(导数)的定义无关紧要:
newton x0 = iterate step x0
where step xn = xn - ((f xn)/(g xn))
我目前正在使用GHCi提示中的take 4 $ newton 3.5
来获取给定列表的第一个元素,但是iterate
返回的列表是无限的,所以我不能在它。
我的想法是在某个margin = 0.0001
之类的地方设置一个常数,当newton函数的最后一次迭代落在边距之后时,iterate
函数停止,我得到了最后一个结果
答案 0 :(得分:4)
仅使用标准功能的duplode答案的变体:
newton :: Double -> Double
newton x0 = (snd . head . dropWhile (not . goal)) (zip approxs (tail approxs))
where
approxs = iterate step x0
step xn = xn - (f xn / g xn)
goal (xa, xb) = abs (xb - xa) < margin
要确定是否已达到目标,我们需要检查iterate
生成的无限列表中相邻的元素对。为此,我们使用标准的技巧来将列表尾部压缩。 (如果您觉得自己比较厚脸皮,请考虑使用(zip <*> tail) approxs
而不是zip approxs (tail approxs)
。这样一来,您不必在表达式中重复提及approxs
,这毫无意义。 )
这给了我们无限对的列表,从中我们删除元素,直到一对组件之间的差异变得足够小。届时,我们提取剩余列表(一对)的开头,并获取第二个分量。
答案 1 :(得分:1)
您想测试newton
生成的成对的连续值。这意味着Prelude中的dropWhile
远远不够,因为它仅测试单个元素。相反,您可以使用 MissingH 中的类似dropWhileList
:
newton :: Double -> Double
newton x0 = dropWhileList (not . goal) (iterate step x0) !! 1
where
step xn = xn - ((f xn)/(g xn))
goal (xa:xb:_) = abs (xb - xa) < margin
goal _ = False
!! 1
为您提供列表的第二个元素。尽管它是部分函数(如果列表没有第二个元素,它将失败),但是在这里使用是安全的(由于iterate
生成了一个无限列表,只要有牛顿方法,您将得到结果收敛)。
答案 2 :(得分:0)
until :: (a -> Bool) -> (a -> a) -> a -> a
...对于实际上不会生成列表的实现:
newton :: Double -> Double
newton = snd . until goal (move . snd) . move
where
step xn = xn - (f xn)/(g xn)
move xn = (xn, step xn) -- The cheeky spelling is (,) <*> step
goal (xa,xb) = abs (xb - xa) < margin
值得将此与melpomene's zip
-based implementation进行比较,并指出其相似之处。