This can be done in O(n log n)
time for arbitrary P
and Q
of degree n
. More precisely this can be done in M(n)
, where M(n)
is the complexity of polynomial multiplication which itself can be done in O(n log n)
.
First of, the first n
terms of a series expansion can be viewed simply as a polynomial of degree n-1
.
Assume you are interested in the first n
terms of the series expansion of P(x)/Q(x)
. There exists an algorithm that will compute the inverse of Q
in M(n)
time as defined above.
Inverse T(x)
of Q(x)
satisfies T(x) * Q(x) = 1 + O(x^N)
. I.e. T(x) * Q(x)
is precisely 1
plus some error term whose coeficients all come after the first n
terms we are interested in, so we can just drop them.
Now P(x) / Q(x)
is simply P(x) * T(x)
which is just another polynomial multiplication.
You can find an implementation that computes the aforementioned inverse in my open source library Altruct. See the series.h file. Assuming you already have a method that computes the product of two polyinomials, the code that calculates the inverse is about 10 lines long (a variant of divide-and-conquer).
The actual algorithm is as follows:
Assume Q(x) = 1 + a1*x + a2*x^2 + ...
. If a0
is not 1
, you can simply divide Q(x)
and later its inverse T(x)
with a0
.
Asume that at each step you have L
terms of the inverse so that Q(x) * T_L(x) = 1 + x^L * E_L(x)
for some error E_L(x)
. Initially T_1(X) = 1
. If you plug this in in the above you'll get Q(x) * T_1(x) = Q(x) = 1 + x^1 * E_1(x)
for some E_1(x)
which means this holds for L=1
. Let's now double L
at each step. You can get E_L(x)
from the previous step as E_L(x) = (Q(x) * T_L(x) - 1) / x^L
, or implementation-wise, just drop the first L
coefficients of the product. You can then compute T_2L(x)
from the previous step as T_2L(x) = T_L(x) - x^L * E_L(x) * T_L(x)
. The error will be E_2L(x) = - E_L(x)^2
. Let's now check that the induction step holds.
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.
I am pretty sure it is not possible to compute polynomial division more efficient than multiplication, and as you can see in the following table, this algorithm is only 3 times slower than a single multiplication:
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
1 / Q(x)
with long division? I thought with division I only find quotient and remainder. – Maypole