Skip to content

08_root_finding_and_quadrature.cpp

Root finding with bisection, Newton, secant and Brent, and five quadrature rules.

Each root finder returns a root_result<T> holding the root, the iterations taken and the final residual. The quadrature rules integrate a callable over [a, b], and the table compares them on \(\int_0^\pi \sin x\,dx = 2\).

#include <cmath>
#include <cstdio>
#include <numbers>
#include <numerics.hpp>
#include <string_view>
#include <vector>

using namespace num;

int main(int argc, char **argv) {
    const bool plot = argc > 1 && std::string_view(argv[1]) == "--plot";

    // The root of x^2 - 2 on [1, 2] is sqrt(2).
    const auto f = [](real x) { return (x * x) - 2.0; };
    const auto df = [](real x) { return 2.0 * x; };
    const real root = std::sqrt(2.0);
    auto report = [&](const char *name, const root_result<real> &r) {
        std::printf("%-10s root %.12f  error %.1e  iterations %2zu\n", name, r.root,
                    std::abs(r.root - root), static_cast<std::size_t>(r.iterations));
    };
    report("bisection", bisection(f, 1.0, 2.0, 1e-12, 100));
    report("newton", newton(f, df, 1.0, 1e-12, 100));
    report("secant", secant(f, 1.0, 2.0, 1e-12, 100));
    report("brent", brent(f, 1.0, 2.0, 1e-12, 100));

    const auto g = [](real x) { return std::sin(x); };
    const real pi = std::numbers::pi;
    std::printf("\nintegral of sin on [0, pi] = 2\n");
    std::printf("trapz, 100 points        error %.1e\n", std::abs(trapz(g, 0.0, pi, 100) - 2.0));
    std::printf("simpson, 100 points      error %.1e\n", std::abs(simpson(g, 0.0, pi, 100) - 2.0));
    std::printf("gauss_legendre, 5 nodes  error %.1e\n", std::abs(gauss_legendre(g, 0.0, pi, 5) - 2.0));
    std::printf("adaptive_simpson 1e-10   error %.1e\n",
                std::abs(adaptive_simpson(g, 0.0, pi, 1e-10) - 2.0));
    std::printf("romberg 1e-10            error %.1e\n", std::abs(romberg(g, 0.0, pi, 1e-10) - 2.0));

    if (plot) {
        std::vector<double> x, y;
        for (int i = 0; i <= 40; ++i) {
            x.push_back(i * 0.05);
            y.push_back(f(i * 0.05));
        }
        plt::plot(x, y, "x^2 - 2", "lines");
        plt::title("08 Root at sqrt(2)");
        plt::show();
    }
}

Possible output:

bisection  root 1.414213562373  error 2.4e-13  iterations 38
newton     root 1.414213562373  error 0.0e+00  iterations  6
secant     root 1.414213562373  error 2.2e-16  iterations  7
brent      root 1.414213562373  error 4.1e-14  iterations  6

integral of sin on [0, pi] = 2
trapz, 100 points        error 1.6e-04
simpson, 100 points      error 1.1e-08
gauss_legendre, 5 nodes  error 1.1e-07
adaptive_simpson 1e-10   error 6.7e-16
romberg 1e-10            error 8.9e-16