One powerful technique when working with polynomials is taking a set of evaluations of that polynomial and using that _directly_ to compute an evaluation at a different point. For example, if $P(x)$ is a degree-100 polynomial, you can use the evaluations $P(0), P(1) ... P(100)$ to directly compute $P(101)$, or $P(1247130)$, in $O(N)$ time, without ever reconstructing the polynomial. This post describes how this is done
Ps: You guys can find fun in [smashy road online](https://smashy-road.io) if you play it happily.
_See also, this earlier and more detailed paper by Oxford researchers on the topic: https://people.maths.ox.ac.uk/trefethen/barycentric.pdf_
## General technique
Let $P(x)$ be the polynomial, and $x_1 ... x_N$ as the set of points for which we have evaluations of $P(x)$. Call these evaluations $y_1 ... y_N$.
Think of $P(x)$ as a linear combination $\sum_i y_i L_i(x)$, where $L_i(x)$ is the polynomial that equals 1 at $x_i$ and 0 at all the other x-coordinates in the set.
Now, let us explore how these $L_i$ can be computed. Each $L_i(x)$ can be expressed as:
$$\frac{(x - x_1)(x - x_2)...(x - x_{i-1})(x - x_{i+1}) ... (x - x_N)}{(x_i - x_1)(x_i - x_2)...(x_i - x_{i-1})(x_i - x_{i+1}) ... (x_i - x_N)}$$
To see why this is true, notice that the numerator of the fraction is a polynomial that equals 0 at every evaluation point except $x_i$, and the denominator is just whatever the numerator equals at $x_i$. Hence, the result equals 0 at every evaluation point except $x_i$, and 1 at $x_i$.
Let us denote this denominator $d_i$. Let us also denote the product $(x - x_1)(x - x_2) ... (x - x_N)$ (_without_ skipping any indices) $M(x)$. We can now express $L_i(x)$ as:
$$\frac{M(x)}{d_i(x - x_i)}$$
The $d_i$ values take $O(N^2)$ time to compute (because each one takes $O(N)$ time and there are $N$ of them), but their values depend only on the evaluation points, not the specific polynomial. Hence, they can be precomputed and stored and don't need to be re-computed each time. $M(x)$ takes $O(N)$ time to compute at any specific point. Given these values, each $L_i(x)$ can be computed in $O(N)$ time. Hence, the expression:
$$P(x) = M(x) * \sum_i \frac{y_i}{d_i(x - x_i)}$$
can be computed in $O(N)$ time.
## Special case: roots of unity
In many applications of barycentric evaluation, we can choose the evaluation points. One very convenient choice is the set $\{1, \omega, \omega^2 ... \omega^{N-1}\}$, for an $\omega$ where $\omega^N = 1$ and $N$ is a power of two. The main advantage of this choice is that it removes the need to pre-compute the $d_i$ values, because there is a simple closed-form value for them.
To see why, let us try to simplify the expression for $d_i$:
$$\prod_{0 \le j \ne i < N} (\omega^i - \omega^j)$$
Notice that $\omega^{\frac{N}{2}} = -1$. We can re-express the above as:
$$2 \omega^i * \prod_{0 \le j \ne i < \frac{N}{2}} (\omega^i - \omega^j)(\omega^i + \omega^j)$$
Each term inside the product groups together $(\omega^i - \omega^j)$ and $(\omega^i - \omega^{j + \frac{N}{2}})$, as $\omega^{j + \frac{N}{2}} = -\omega^j$. The term on the left is for $(\omega^i - \omega^{i + \frac{N}{2}})$, which simplifies to $2\omega^i$ for the same reason.
Now, notice that $(\omega^i - \omega^j)(\omega^i + \omega^j)$ combines into $(\omega^{2i} - \omega^{2j})$. So we have:
$$2 \omega^i * \prod_{0 \le j \ne i < \frac{N}{2}} (\omega^{2i} - \omega^{2j})$$
Repeat this, and we have:
$$2 \omega^i * 2 \omega^{2i} * \prod_{0 \le j \ne i < \frac{N}{4}} (\omega^{4i} - \omega^{4j})$$
Keep repeating, and we get:
$$2 \omega^i * 2 \omega^{2i} * 2\omega^{4i} * ... * 2\omega^{\frac{N}{2}i}$$
The product term on the right falls away because the product eventually becomes empty. The remaining term simply becomes $N * \omega^{(N-1)i}$, or:
$$d_i = \frac{N}{\omega^i}$$
Additionally, note that $M(x) = \prod_i (x - \omega^i)$ simply becomes $x^N - 1$, so the entire calculation simplifies down to:
$$P(x) = \frac{x^N - 1}{N} * \sum_i \frac{y_i * \omega^i}{x - \omega^i}$$