高效生成泰勒(Maclaurin)系列

时间:2014-05-23 05:52:08

标签: algorithm calculus taylor-series

考虑函数
y = 1 /((1-x ^ 5)(1-x ^ 7)(1-x ^ 11))

WolframAlpha在几秒钟内计算MacLaurin系列扩展的前1000个元素:
https://www.wolframalpha.com/input/?i=maclaurin+series+1%2F%28%281-x%5E5%29%281-x%5E7%29%281-x%5E11%29%29

出于好奇,我写了一个非常天真的java程序来使用BigInteger对多项式系数做同样的事情。在伪代码中,它将类似于:

BigInt next=1;
BigInt factorial=1;
while(true){
   function=function.differentiate();
   factorial*=++next;
   print("Next coefficient is: " + function(0)/factorial);
}

在计算前七个或大约系数之后,该程序与java.lang.outofmemory异常崩溃,因为分数的分子和分母变成了非常长的多项式。假设我的代码效率低下,但似乎Wolfram使用的技术与第一年的微积分类相同。
问题是:Wolfram使用了什么?

为了比较,Wolfram花费了相当多的时间来计算相同函数的十个导数,而不是获得前1000个多项式项,如果天真地完成,则需要将函数区分1000次。
https://www.wolframalpha.com/input/?i=tenth+derivative+1%2F%28%281-x%5E5%29%281-x%5E7%29%281-x%5E11%29%29

4 个答案:

答案 0 :(得分:2)

不确定分数的分子,但我可以看出为什么它的分母增长得太快了:

factorial*=factorial+1;

不是你计算阶乘的方法。那个不仅仅是正方形" factorial"每次迭代时分母的值!所以你会得到1,2,6,42,1806,3263442 ......相比之下,阶乘法则分别为1,2,6,24,120,720 ...

要逐步计算阶乘,请维护一个循环计数器,并每次将factorial乘以

答案 1 :(得分:2)

tl; dr:x N 的系数是仅使用5,7和11分割N的方式。

我不确定Wolfram是如何做到的,但是对于这个函数,可以更有效地计算系数(使用你在第一年结束时看到的微积分技术)。作为幂级数,1 /(1-x)=Σ k = 0 x k 。但我们可以用x n 替换x,并且该关系仍然有效。这意味着 1 /((1-x 5 )(1-x 7 )(1-x 11 ))=(Σ k = 0 X 5K )(Σ<子> K = 0 X 7K < / SUP>)(Σ<子> K = 0 X 11K

将这一点乘以将是一种痛苦。但是所有的系数都是1,所以我们只需要看一下加在一起的指数。例如,Wolfram表明x 40 的系数是4,它来自(x 5·1 )(x 7·5 ) (X 0·11 )+(X 5·0 )(X 7·1 )(X 11·3 )+(X 5·3 )(X 7·2 )(X 11·1 )+(X 5 ·8 )(X 7·0 )(X 11·0 )。

但是如果我们只需要添加指数,那么我们就不需要关心系数或变量x。最后,x N 的系数是N可以写成5s,7s和11s之和的方式的数量。这是分区问题的限制版本,但同样的想法仍然适用。特别是,动态编程方法能够计算线性时间和空间中的系数。

答案 2 :(得分:0)

理性函数(以及这个特定函数)既不需要区分也不需要因子。计算序列的一种方法是将每个因子扩展为其自身的序列(例如1/(1 - x^5) = sum(n=[0,inf] x^(5n)),然后将结果乘以多项式。

答案 3 :(得分:0)

你可以在正式的电力系列上进行每项操作。给定f,g的幂级数,你可以找到f(z)+ g(z),f(z)g(z),f(z)/ g(z),f(g(g)的幂级数的递推关系。 z)),甚至f ^ -1(z)。使用这些方法,您可以计算多项式时间内几乎任何函数的幂级数。

在特殊情况下,有更有效的方法。如果f(z)具有幂级数,则f(z)/(1-z)的幂级数的系数仅仅是f(z)的幂级数的部分和。因此,如果f_n是f的系列,则g(z)= f(z)/(1-z)的系列由g_n = f_n + g_(n-1)给出。

您可以通过任何多项式将其扩展为除法。该算法与多项式的长除法基本相同。例如,让我们计算1 /(1 - z ^ 2)。我们将z ^ 2加上和减去分子得到(1-z ^ 2 + z ^ 2)/(1-z ^ 2)= 1 + z ^ 2 /(1-z ^ 2)。然后我们加上和减去z ^ 4得到(z ^ 2 - z ^ 4 + z ^ 4)/(1 - z ^ 2)= z ^ 2 + z ^ 4 /(1 - z ^ 2)。继续这样你会发现1 /(1 - z ^ 2)= 1 + z ^ 2 + z ^ 4 + z ^ 6等等。

对于度数为n的一般多项式执行此操作时,总是使用小于n个项的分子。您可以将这些术语的系数存储在数组中,并将其用作您的状态。从一个状态,您可以计算幂级数中的下一个项和下一个时间状态O(n)。这为您提供了一个O(nk)时间算法来查找1 / p(z)幂级数中的前k个项。

请注意,在点z = z0处计算幂级数与在z = z0处查找所有导数相同,因此这两个问题是等价的。您可以在符号变量点计算幂级数以找到导数的公式,因此理论上没有理由认为Wolfram在找到第n个导数时要慢得多。