考虑函数
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
答案 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个导数时要慢得多。