【问题标题】:Integration via trapezoidal sums in MATLAB通过 MATLAB 中的梯形求和进行积分
【发布时间】:2014-10-10 03:16:04
【问题描述】:

我需要帮助来使用梯形和求函数的积分。

程序应该对n = 1, 2, 3, ... 进行连续的梯形求和 子间隔,直到有两个相邻的 n 值相差小于给定容差。我希望在WHILE 循环中至少有一个FOR 循环,并且我不想使用trapz 函数。该程序有四个输入:

  • fx 函数的函数句柄。
  • a:一个实数。
  • b:大于a 的实数。
  • tolerance:一个非常小的正数实数

我遇到的问题是尝试实现梯形和的公式,即 Δx/2[y0 + 2y1 + 2y2 + … + 2yn-1 + yn]

这是我的代码,我陷入的区域是FOR 循环中的“总和”部分。我试图总结2y2 + 2y3....2yn-1,因为我已经考虑了2y1。我得到了答案,但它并不像应有的那样准确。例如,我得到6.071717974723753 而不是6.101605982576467

感谢您的帮助!

function t=trapintegral(f,a,b,tol)
format compact; format long;
syms x;
oldtrap = ((b-a)/2)*(f(a)+f(b));
n = 2;
h = (b-a)/n;
newtrap = (h/2)*(f(a)+(2*f(a+h))+f(b));
while (abs(newtrap-oldtrap)>=tol)
    oldtrap = newtrap;
    for i=[3:n]
        dx = (b-a)/n;
        trapezoidsum = (dx/2)*(f(x) + (2*sum(f(a+(3:n-1))))+f(b));
        newtrap = trapezoidsum;
    end
end
t = newtrap;
end

【问题讨论】:

  • “在每 n 个子区间创建更多梯形之后” - 不清楚你的意思。
  • 每n个子区间后,曲线下的梯形数增加
  • Trapezoidal integration 包含在核心 Matlab 中,请参阅trapz,如果您对它的实现方式感兴趣,请查看源代码:edit trapz。顺便说一句,在编写 Matlab 时应尽可能避免循环。

标签: matlab math sum integration integral


【解决方案1】:

此代码不起作用的原因是您对梯形规则的求和中有两个小错误。我所指的正是这种说法:

trapezoidsum = (dx/2)*(f(x) + (2*sum(f(a+(3:n-1))))+f(b));

回忆梯形积分规则的方程:

来源:Wikipedia

对于第一个错误,f(x) 应该是 f(a),因为您包含了起点,并且不应保留为符号。事实上,您应该简单地去掉 syms x 语句,因为它在您的脚本中没有用处。 a 对应于x1,通过查阅上述等式。

下一个错误是第二项。您实际上需要将索引值(3:n-1) 乘以dx。此外,这实际上应该来自(1:n-1),我稍后会解释。上面的等式从 2 变为 N,但出于我们的目的,我们将从 1 变为 N-1,因为您的代码设置是这样的。

请记住,在梯形规则中,您将有限区间细分为n 部分。第 ith 块定义为:

x_i = a + dx*i;  ,

其中i1N-1。请注意,这是从 1 而不是 3 开始的。原因是因为第一块已经被 f(a) 考虑在内,而我们只计算到 N-1 作为一块 N 是由f(b) 计算。对于等式,它从 2 变为 N,通过这种方式修改代码,这正是我们最终要做的。

因此,你的陈述实际上需要是:

trapezoidsum = (dx/2)*(f(a) + (2*sum(f(a+dx*(1:n-1))))+f(b));

试试这个,如果你得到正确的答案,请告诉我。 FWIW,MATLAB 已经通过 @ADonda 已经指出的 trapz 实现了梯形集成。但是,在设置之前,您需要正确构建 xy 值。换句话说,您需要事先设置您的dx,然后使用我上面指定的x_i 等式计算您的x 点,然后使用这些来生成您的y 值。然后使用trapz 计算面积。换句话说:

dx = (b-a) / n;
x = a + dx*(0:n);
y = f(x);
trapezoidsum = trapz(x,y);

你可以参考上面的代码来看看你是否正确的实现了梯形规则。您的实现和使用上面的代码应该会产生相同的结果。您所要做的就是更改n 的值,然后运行此代码以生成曲线下方不同细分区域的近似值。


编辑 - 2014 年 8 月 17 日

我知道为什么您的代码不起作用。原因如下:

  1. for 循环是不必要的。看看for 循环迭代。您有一个从 i = [3:n] 开始的循环,但您不要在循环中完全引用 i 变量。因此,您根本不需要这个。

  2. 您没有正确计算连续间隔。您需要做的是在计算nth 子区间的梯形和时,然后增加 n 的值,然后再次计算梯形规则。此值在您的 while 循环中没有正确增加,这就是您的区域从未改善的原因。

  3. 您需要将前一个区域保存在while 循环中,然后在计算下一个区域时,即确定区域之间的差异是否小于容差。我们也可以去掉一开始尝试计算n = 2 的区域的代码。这不是必需的,因为我们可以将它放在您的 while 循环中。因此,您的代码应该是这样的:


function t=trapintegral(f,a,b,tol)
format long; %// Got rid of format compact. Useless
%// n starts at 2 - Also removed syms x - Useless statement
n = 2;
newtrap = ((b-a)/2)*(f(a) + f(b)); %// Initialize
oldtrap = 0; %// Initialize to 0
while (abs(newtrap-oldtrap)>=tol)
    oldtrap = newtrap; %//Save the old area from the previous iteration
    dx = (b-a)/n; %//Compute width
    %//Determine sum
    trapezoidsum = (dx/2)*(f(a) + (2*sum(f(a+dx*(1:n-1))))+f(b));
    newtrap = trapezoidsum; % //This is the new sum
    n = n + 1; % //Go to the next value of n
end
t = newtrap;
end

通过运行你的代码,我得到了:

trapezoidsum = trapintegral(@(x) (x+x.^2).^(1/3),1,4,0.00001)

trapezoidsum = 

6.111776299189033

警告

看看我定义你的函数的方式。您必须使用逐个元素的操作,因为循环内的sum 命令将被矢量化。具体看一下^ 操作。您需要在操作前添加一个点。一旦你这样做,我就会得到正确的答案。

编辑 #2 - 2014 年 8 月 18 日

您说您至少需要一个for 循环。这是非常低效的,并且在代码中指定有一个 for 循环的人真的不知道 MATLAB 是如何工作的。不过,您可以使用for 循环来累积sum 术语。因此:

function t=trapintegral(f,a,b,tol)
format long; %// Got rid of format compact. Useless
%// n starts at 3 - Also removed syms x - Useless statement
n = 3;
%// Compute for n = 2 first, then proceed if we don't get a better
%// difference tolerance
newtrap = ((b-a)/2)*(f(a) + f(b)); %// Initialize
oldtrap = 0; %// Initialize to 0
while (abs(newtrap-oldtrap)>=tol)
    oldtrap = newtrap; %//Save the old area from the previous iteration
    dx = (b-a)/n; %//Compute width
    %//Determine sum
    %// Initialize
    trapezoidsum = (dx/2)*(f(a) + f(b));

    %// Accumulate sum terms
    %// Note that we multiply each term by (dx/2), but because of the
    %// factor of 2 for each of these terms, these cancel and we thus have dx
    for n2 = 1 : n-1
        trapezoidsum = trapezoidsum + dx*f(a + dx*n2);
    end
    newtrap = trapezoidsum; % //This is the new sum
    n = n + 1; % //Go to the next value of n
end
t = newtrap;
end

祝你好运!

【讨论】:

  • 您好,感谢您的回复。我正在尝试在不使用 trapz 的情况下编写代码,所以我使用了您的第一个建议,但答案并不像应有的那样接近。例如 trapintegral(@(x) (x+x^2)^(1/3),1,4,0​​.00001) 应该产生 6.111776299189035 但我得到 6.071717974723753 代替。我又摆弄了一些,但我无法得到改变的答案
  • @BruceWayne 我想通了。你写错了loop。您没有正确比较连续的 n 子间隔。我会尽快回复。
  • 好的,感谢您指出循环问题。但我在 while 循环中至少需要 1 个 FOR 循环。我了解您编写的代码,但我无法在 for 循环的某个地方实现。感谢您到目前为止的帮助! :)
  • @BruceWayne - 为什么至少需要一个 for 循环?那是非常低效的。我会修改代码,但我强烈建议不要使用 for 循环。
  • 我知道,对此我很抱歉,但这只是我希望我的代码包含的内容。不过,非常感谢您迄今为止的投入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-21
  • 2018-01-12
  • 1970-01-01
相关资源
最近更新 更多