Bernstein polynomials and the Weierstrass theorem#

Weierstrass proved in 1885 that every continuous function on a closed interval is a uniform limit of polynomials. Sergei Bernstein’s 1912 proof builds the polynomials explicitly: average \(f(k/n)\) with binomial weights. This script approximates a function with a kink, \(|x - 1/2|\), and shows the uniform error shrinking, slowly, as the degree grows.

import matplotlib.pyplot as plt
import numpy as np

from mathematicskit.numerical_analysis import bernstein_polynomial

Bernstein approximants of increasing degree#

f = lambda t: np.abs(t - 0.5)
x = np.linspace(0.0, 1.0, 501)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4.2))
ax1.plot(x, f(x), "k", lw=2, label="$|x - 1/2|$")
for n in (4, 16, 64, 256):
    ax1.plot(x, bernstein_polynomial(f, n, x), label=f"$B_{{{n}}}f$")
ax1.set_title("Bernstein polynomials")
ax1.legend(fontsize=8)
Bernstein polynomials
<matplotlib.legend.Legend object at 0x119f730e0>

Uniform error against degree#

degrees = np.array([2, 4, 8, 16, 32, 64, 128, 256, 512])
errors = np.array([np.max(np.abs(bernstein_polynomial(f, n, x) - f(x))) for n in degrees])
ax2.loglog(degrees, errors, "o-", label="max error")
ax2.loglog(degrees, 0.4 / np.sqrt(degrees), "--", color="gray", label=r"$\propto n^{-1/2}$")
ax2.set_xlabel("degree $n$")
ax2.set_title("Convergence is uniform but slow")
ax2.legend(fontsize=8)
fig.tight_layout()

for n, e in zip(degrees, errors):
    print(f"n = {n:4d}: max |B_n f - f| = {e:.4f}")

plt.show()
n =    2: max |B_n f - f| = 0.2500
n =    4: max |B_n f - f| = 0.1875
n =    8: max |B_n f - f| = 0.1367
n =   16: max |B_n f - f| = 0.0982
n =   32: max |B_n f - f| = 0.0700
n =   64: max |B_n f - f| = 0.0497
n =  128: max |B_n f - f| = 0.0352
n =  256: max |B_n f - f| = 0.0249
n =  512: max |B_n f - f| = 0.0176

Total running time of the script: (0 minutes 0.105 seconds)

Gallery generated by Sphinx-Gallery