按条件停止迭代循环并返回与条件匹配的值
Stopping an iterate loop by a condition and returning the value that matched the condition
我正在尝试在 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
或类似的东西,当牛顿函数的最后一次迭代落后于边际时,iterate
函数停止,我有最终结果
您想测试 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
生成一个无限列表,只要牛顿法你就会得到一个结果收敛)。
仅使用标准函数的 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
,这确实有点毫无意义。 )
这给了我们一个无限的对列表,我们从中删除元素,直到一对组件之间的差异变得足够小。那时我们提取剩余列表(一对)的头部并获取第二个组件。
正在取货oisdk's suggestion of using 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
值得将其与 进行比较并注意相似之处。
我正在尝试在 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
或类似的东西,当牛顿函数的最后一次迭代落后于边际时,iterate
函数停止,我有最终结果
您想测试 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
生成一个无限列表,只要牛顿法你就会得到一个结果收敛)。
仅使用标准函数的 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
,这确实有点毫无意义。 )
这给了我们一个无限的对列表,我们从中删除元素,直到一对组件之间的差异变得足够小。那时我们提取剩余列表(一对)的头部并获取第二个组件。
正在取货oisdk's suggestion of using 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
值得将其与