You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Haskell中通过函数参数实现牛顿-拉夫逊法求根?

修复牛顿-拉夫逊算法的Haskell实现问题

错误原因解析

你遇到的No instance for (Show (Double -> Double))错误,是因为你尝试打印一个函数对象而非数值结果。比如如果调用时只输入了newtonR f g(漏传初始点x0),返回的是Double -> Double类型的函数,而Haskell无法直接打印函数,就会触发这个错误。确保调用时传全三个参数:newtonR f g (-1.5)。

原代码的核心问题

  1. 浮点数直接比较相等/不等完全不可靠:浮点数存在精度误差,永远不要用x /= 0或x1 == x2判断收敛,必须用精度阈值(如1e-8)判断两次迭代的差值是否足够小。
  2. 缺少除以0的防护:如果迭代中导数为0,会直接崩溃,需要提前判断并处理。
  3. 递归逻辑冗余:每次递归都重复传递f和g参数,不够简洁。

修正后的实现

newtonR :: (Double -> Double) -> (Double -> Double) -> Double -> Double
newtonR f g x0 = newtonIter x0
  where
    epsilon = 1e-8  -- 自定义收敛精度,可根据需求调整
    newtonIter x =
      let fx = f x
          gx = g x
      in if abs gx < epsilon  -- 导数接近0时,终止迭代返回当前值
           then x
           else let xNext = x - fx / gx
                in if abs (xNext - x) < epsilon  -- 满足收敛条件则返回
                     then xNext
                     else newtonIter xNext

测试示例

(注意你提供的示例中函数和导数不匹配,以下是修正后的对应函数)

-- 目标函数:f(x) = x³ - 2x + 1
f x = x^3 - 2*x + 1
-- 导数:f’(x) = 3x² - 2
g x = 3*x^2 - 2

-- 调用并打印结果
main = print $ newtonR f g (-1.5)
-- 输出结果接近:-1.61803398875

额外说明

  • 显式添加类型签名(Double -> Double) -> (Double -> Double) -> Double -> Double,能提前发现类型不匹配的问题,提升代码可读性。
  • 内部嵌套的newtonIter函数避免了重复传递f和g,简化递归逻辑。
  • 精度阈值epsilon可根据场景调整:需要更高精度就设更小的值(如1e-12),需要更快收敛就设更大的值。

内容的提问来源于stack exchange,提问作者Joel Giroud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:25:43