【问题标题】:Trapezoid Rule in HaskellHaskell 中的梯形规则
【发布时间】:2017-11-30 17:38:36
【问题描述】:

我正在尝试在 Haskell 中定义梯形规则。我创建了一个辅助函数 innerSum,它是梯形规则的总和部分。然后在积分定义中,我乘以距离并取下界、上界、一个函数和一些 n 个梯形。随着 n 的增加,答案应该变得更加准确。我的功能似乎适用于大多数情况

除了这种情况(可能还有其他情况): 定积分 (-1) 1 (\x->x^100) 20.

当我将值更改为 20 而不是我的答案偏离某个特定值并变得更准确时,数字只是随机跳跃。我似乎找不到错误

definiteIntegral :: Double -> Double -> (Double -> Double) -> Integer -> Double
definiteIntegral a b g n | a <= b = (dist a b n)*(innerSum a b g (dist a b n))
                         | otherwise = (dist a b n)*(innerSum b a g (dist b a n))
                         where dist a b n = (b-a)/(fromIntegral n::Double)

innerSum :: Double -> Double -> (Double -> Double) -> Double -> Double
innerSum a b g d | a >= b = 0
                 | otherwise = (((g a) + (g (a + d)))/2)+(innerSum (a + d) b g d) 

【问题讨论】:

  • 我不认为这是特定于 Haskell 的问题,但与浮点运算导致的数值精度和舍入误差有关。
  • 它不会因此完全准确,是的,但它仍然不会跳得那么剧烈
  • 另请注意,如果您增加三角形的数量definiteIntegral (-1) 1 (^100) 100000,您将非常接近“正确答案”2/101=0.0198

标签: haskell integration


【解决方案1】:

问题是你的结束条件。你计算步长,所以原则上,你应该在n 步之后正好在正确的边界处结束。如果您确保步长可以用浮点数精确表示,即 2 的幂的倍数,那确实会起作用:

*Main> definiteIntegral (-1) 1 (^100) <$> [64, 128, 256, 512, 1024]
[3.396429282002939e-2,2.3718601030590182e-2,2.08093271780123e-2,2.0055667986086628e-2,1.9865519301509465e-2]
     -- convergence towards 1.98×10⁻²

但大多数数字can not be exactly represented in FP,因此您经常不会准确地到达正确的边界。如果最后一点略低于该界限,则算法将执行一个完整的额外步骤,即您将一个小的浮点误差放大为一个整步误差。从数值上讲,它“只是”一个 1 阶错误,因为随着分辨率的增加,单步大小会变得越来越小。 (仍然很糟糕,因为梯形规则实际上应该是二阶准确的!)

(^100) 的问题尤其是:该函数在区间 [-1,1] 的大部分时间都非常接近于零,但在 &pm;1 附近增长得非常快。因此区间的结果由紧邻边界的飞人控制,更受边界外的飞人控制!

最简单的解决方法是去掉 innerSum 函数并改用内置工具:

definiteIntegral :: Double -> Double -> (Double -> Double) -> Integer -> Double
definiteIntegral a b g n
    | a <= b = - definiteIntegral b a g n
    | otherwise = δ * sum [ (g x + g (x+δ))/2
                          | x <- [a, a+δ .. b] ]
 where δ = (b-a) / fromIntegral n

in this question 解释了为什么即使步长没有精确表示也能可靠工作:如果前一个已经接近边界而下一个将拒绝采取额外的步骤,例如 [a, a+δ .. b]带你超越界限。

【讨论】:

  • 只是为了澄清 FP 在这里是浮点而不是函数式编程?!
  • @epsilonhalbe 不不,这是一个鲜为人知的事实,数字 42 只能用纯函数式编程语言近似表示,因为否则宇宙将崩溃并被更奇怪的东西所取代......
猜你喜欢
  • 2014-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-29
  • 2016-07-12
  • 2014-12-17
  • 1970-01-01
相关资源
最近更新 更多