我需要在C ++中编写函数来有效地找到给定有理函数(P(x)/ Q(x))的泰勒级数的系数。
函数参数将是多项式的幂(在分母和分母中相等),两个具有多项式系数的数组和扩展中的项数。
我的想法是关注。 考虑身份
P(x) / Q(x) = R(x) + ...
其中R(x)
是一个多项式,其项数等于我需要找到的系数数。然后我可以用Q(x)
将两边相乘并得到
P(x) = R(x) * Q(x)
R(x) * Q(x) - P(x) = 0
因此,所有系数都应为零。这是具有 O(n ^ 3)算法的方程组来求解。 O(n ^ 3)并不像我想的那么快。
有更快的算法吗?
我知道系列的系数满足线性递归关系。 这让我觉得 O(n)算法是可能的。
答案 0 :(得分:5)
我要描述的算法在formal power series数学上是合理的。泰勒系列的每个功能都有一个正式的电源系列。相反的情况并非如此,但如果我们对泰勒级数的函数进行算术运算并得到泰勒级数的函数,那么我们可以用正式的幂级数进行相同的算术并得到相同的答案。
正式幂级数的长除法算法就像你在学校学到的long division算法一样。我将在示例(1 + 2 x)/(1 - x - x^2)
上演示它,其系数等于Lucas numbers。
分母必须具有非零常数项。我们首先编写分子,这是第一个残差。
--------
1 - x - x^2 ) 1 + 2 x
[
我们将残差的最低阶项(1
)除以分母的常数项(1
)并将商数放在最上面。
1
--------
1 - x - x^2 ) 1 + 2 x
现在我们将1 - x - x^2
乘以1
并将其从当前残差中减去。
1
--------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
-------------
3 x + x^2
再做一次。
1 + 3 x
--------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
---------------
3 x + x^2
3 x - 3 x^2 - 3 x^3
-------------------
4 x^2 + 3 x^3
再一次。
1 + 3 x + 4 x^2
----------------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
---------------
3 x + x^2
3 x - 3 x^2 - 3 x^3
-------------------
4 x^2 + 3 x^3
4 x^2 - 4 x^3 - 4 x^4
---------------------
7 x^3 + 4 x^4
再一次。
1 + 3 x + 4 x^2 + 7 x^3
------------------------
1 - x - x^2 ) 1 + 2 x
1 - x - x^2
---------------
3 x + x^2
3 x - 3 x^2 - 3 x^3
-------------------
4 x^2 + 3 x^3
4 x^2 - 4 x^3 - 4 x^4
---------------------
7 x^3 + 4 x^4
7 x^3 - 7 x^4 - 7 x^4
---------------------
11 x^4 + 7 x^5
各个部门有点无聊,因为我使用带有前导1
的除数,但如果我使用了2 - 2 x - 2 x^2
,那么商中的所有系数都会被除以2
。
答案 1 :(得分:2)
这可以在O(n log n)
时间内针对任意P
和Q
度n
进行。更准确地说,这可以在M(n)
中完成,其中M(n)
是多项式乘法的复杂性,其本身可以在O(n log n)
中完成。
首先,系列扩展的第一个n
项可以简单地视为度n-1
的多项式。
假设您对n
系列扩展的第一个P(x)/Q(x)
条款感兴趣。存在一种算法,可以在Q
时间内计算M(n)
的倒数,如上所述。
T(x)
的反向Q(x)
满足T(x) * Q(x) = 1 + O(x^N)
。即T(x) * Q(x)
正好是1
加上一些错误术语,其系数都来自我们感兴趣的第一个n
项,所以我们可以放弃它们。
现在P(x) / Q(x)
只是P(x) * T(x)
,这只是另一个多项式乘法。
您可以在我的开源库Altruct中找到计算上述反转的实现。请参阅series.h文件。假设你已经有一个计算两个多项式的乘积的方法,那么计算逆的代码大约是10行(分而治之的变种)。
实际算法如下:
假设Q(x) = 1 + a1*x + a2*x^2 + ...
。如果a0
不是1
,您只需将Q(x)
及其后的T(x)
与a0
分开即可。
假设您在每个步骤中都有L
个倒数项,以便Q(x) * T_L(x) = 1 + x^L * E_L(x)
出现一些错误E_L(x)
。最初是T_1(X) = 1
。如果您在上面插入此内容,则会Q(x) * T_1(x) = Q(x) = 1 + x^1 * E_1(x)
获得某些E_1(x)
,这意味着这适用于L=1
。现在让我们在每一步加倍L
。您可以将E_L(x)
作为E_L(x) = (Q(x) * T_L(x) - 1) / x^L
从上一步获得,或者在实施方面,只需删除产品的第一个L
系数。然后,您可以将上一步中的T_2L(x)
计算为T_2L(x) = T_L(x) - x^L * E_L(x) * T_L(x)
。错误将是E_2L(x) = - E_L(x)^2
。现在让我们检查归纳步骤是否成立。
Q(x) * T_2L(x)
= Q(x) * (T_L(x) - x^L * E_L(x) * T_L(x))
= Q(x) * T_L(x) * (1 - x^L * E_L(x))
= (1 + x^L * E_L(x)) * (1 - x^L * E_L(x))
= 1^2 - (x^L * E_L(x))^2
= 1 + x^2L * E_2L(x)
Q.E.D。
我很确定计算多项式除法比乘法更有效,正如您在下表中所看到的,这个算法只比单个乘法慢3倍:
n mul inv factor
10^4 24 ms 80 ms 3,33x
10^5 318 ms 950 ms 2,99x
10^6 4.162 ms 12.258 ms 2,95x
10^7 101.119 ms 294.894 ms 2,92x
答案 2 :(得分:1)
如果仔细观察计划中的系统,可以看到它已经是对角线,并且不需要求解O(n ^ 3)。它简单地退化为线性递归(P [],Q []和R []是相应多项式的系数):
R[0] = P[0]/Q[0]
R[n] = (P[n] - sum{0..n-1}(R[i] * Q[n-i]))/Q[0]
由于Q是多项式,因此总和不超过deg(Q)
项(因此需要恒定的时间来计算),使得总体复杂度渐近线性。您还可以查看(可能)更好渐近的递归矩阵表示。