【问题标题】:Making a function sensitive for vector input使函数对向量输入敏感
【发布时间】:2014-03-20 09:04:34
【问题描述】:

这是我的数值方法课程。我正在努力理解 MATLAB 及其语法,但我是 100% 自学的,所以如果我的尝试看起来很荒谬,请多多包涵。

我写了这个非常简单的函数来近似数字 e

function e= calcEulerLimit(n)
e = (1 + 1./n).^n;
end

这是数字 e 的“基本”定义,使用从 n 到无穷大的方法。对于 MATLAB,我定义了以下向量(当我在后者中谈论 n 时,我总是指这个向量n

n=[1:1:10]=[ 1 2 3 4 5 6 7 8 9 10 ]

并且输出工作正常,正如我预期的那样,当我在 MATLAB 中调用我的函数时,它对向量 n 输入很敏感。

>> calcEulerlimit(n)

ans =

    2.0000    2.2500    2.3704    2.4414    2.4883    2.5216    2.5465    2.5658    2.5812    2.5937

现在我想用泰勒方法做与上面完全相同的事情,使用无限求和公式来描述 e,这是我卡住的地方,下面的简单代码可以工作:

function e = calcEulerSum(n)
e=1;                % base-case, start variable
for i=1:1:n       % for loop with step size one
    e=e+1/factorial(i)
end
end 

但是,当我想输入一个向量(例如 n)时,这个输入当然不起作用,它通过所有变量进行计算。

我尝试了另一个 for 循环和一个 while 循环,但 while 循环似乎永远不会终止:

function e = calcEulerSum3(n)
while n
e=1;
e = e + 1./cumprod(n);
end
end

使用cumprod(n) 获取我的向量n 的每个列元素的阶乘值。

【问题讨论】:

    标签: matlab


    【解决方案1】:

    您正在尝试矢量化您的函数。您的标量解决方案有效,所以让我们看看它在增加 i 时的作用:

           e0 = 1;
    i = 1: e(1) = e0 + 1/factorial(1)
    i = 2: e(2) = e(1) + 1/factorial(2) = e0 + 1/factorial(1) + 1/factorial(2)
                                        = e0 + sum(1./factorial(1:2))
    i = 3: e(3) = e(2) + 1/factorial(3) = ...
                                        = e0 + sum(1./factorial(1:3))
        ...
    i = n: e(n) = e(n-1) + 1/factorial(n) = e0 + 1/factorial(1) + ... + 1/factorial(n)
                                          = e0 + sum(1./factorial(1:n))
    

    那么你能想出一个通用表达式来计算给定n 的向量e 吗? cumsum 函数会派上用场。

    【讨论】:

    • 感谢您的回答,我将阅读有关 cumsum 的信息,到目前为止,我在 for i=n, e=1, e= e + 1./factorial(n);这对我来说似乎很清楚,但我得到的输出是 2, 1.5, 1.1667, 1.0417 所以除了加法部分之外它似乎“有效”。
    • @Spaced: n 是一个向量。如果您使用for 循环,您可能需要对其进行索引:n(i)。您可能还需要将输出保存在向量中:e(i)
    • 参见我上面的伪代码示例。输出e 将是一个向量,对吧?你能计算出e的第一个元素吗?给定第一个元素,您现在可以计算第二个元素(i=2)吗?等等...您可以在for 循环中执行此操作,然后您可能会看到如何使用cumsum 在一行代码中实现所有这些。
    • 基本情况是 1,第一个是 2,第二个是 2.5,这样它会收敛到 e。老实说,我不能仅从您的代码中看到 e 将成为一个向量,但我可以接受。我可以看到您首先引入了递归定义,然后在最后一行中您说它是基本元素加上所有 1/k 的总和!术语,这在数学上确实是正确的。所以例如 e=1; e= e+ sum(1./factorial(1:10)) 将导致正确答案 2.7183,但是是否可以告诉 Matlab 分别输出每个迭代?
    • 例如,当我像这样计算函数(没有 for 循环)时 e=1; e= e + sum(1./factorial(1:n)) 其中 n 仍然是我定义的向量(如上面提到的问题 n= 1:10),那么输出将只是 2。如果我改为输入 e = e + sum(1./factorial(n)),我得到正确的结果 2.718,但我希望我的输出如上例所示:2、2.5、2.568 等等。
    【解决方案2】:

    for i=whatsoever,statement(i);endwhatsoever 的每个元素执行语句。如果是单个数字,则在这个数字上,如果是向量/数组,则在它的每个元素上。

    1:1:n 在现场创建一个从1n 的整数数组(1:n 也可以)。如果n 已经是一个包含要迭代的元素的向量,则可以直接使用它:for i=n

    但是,为什么您在第一个和第三个代码块中使用了操作的虚线版本,而不是您的第二个?因为你读过 MATLAB 的向量化?那么您似乎走在了正确的轨道上,但请记住,点矢量化是为了完全摆脱显式循环。

    【讨论】:

    • 非常感谢您的解释@arne.b 我正在阅读我可以在网上找到的所有 Matlab 手册,在第二个示例中,我将除以阶乘(i),这将始终是数字。但是,在第三个示例中,我将除以向量,并且我已经阅读过,在这种情况下,我必须使用 ./ 来指定逐元素除法。输出确实有效,但它不正确。我会尝试更好地理解它。
    • @horchler “减少显式循环的数量”怎么样?至少,如果之前有一个 for 循环,之后有一个 while 循环做同样的事情,那么就没有矢量化。 :-)
    • @arne.b:您的编辑版本要好得多(更精确/更谨慎)。我投票赞成您解释for 循环如何与向量一起使用。
    【解决方案3】:
    function e = calcEulerSum(n)
    e=nan(1,length(n));                % initialize to nan
    for j=1:length(n)                % for each element in the input
        e(j)=sum(1./factorial(0:n(j))); %each entry is computed in this step, one at a time
    end 
    

    在这段代码中,每个近似值都被向量化了,但我没有看到一个简单的方法来向量化整个程序。也没有错误检查,比如确保 n 的元素是非负整数,或者 n 是向量而不是数组。

    在原始示例中,while 永远不会终止,因为 n 永远不会改变。

    这应该足以帮助您入门。

    干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-23
      • 1970-01-01
      • 1970-01-01
      • 2021-03-09
      • 1970-01-01
      • 1970-01-01
      • 2021-05-20
      • 2016-01-11
      相关资源
      最近更新 更多