通过条件停止迭代循环并返回与条件匹配的值

时间:2019-05-18 21:57:16

标签: haskell newtons-method

我正在尝试在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函数停止,我得到了最后一个结果

3 个答案:

答案 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)

采纳oisdk关于使用until的建议...

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进行比较,并指出其相似之处。