Rational函数系列扩展的最佳算法

时间:2014-04-15 19:19:14

标签: c++ algorithm taylor-series

我需要在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)算法是可能的。

3 个答案:

答案 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)时间内针对任意PQn进行。更准确地说,这可以在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)项(因此需要恒定的时间来计算),使得总体复杂度渐近线性。您还可以查看(可能)更好渐近的递归矩阵表示。