// (C) Copyright Nick Thompson 2018. // (C) Copyright Matt Borland 2026. // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Module build check for the finite-difference numerical differentiation // component. Consuming boost.math as a named module, this exercises both public // entry points, finite_difference_derivative across every supported order and // complex_step_derivative, using functions whose derivatives are exact and // mathematically certain (polynomials) so no library helpers are needed to // produce the expected values. #ifndef BOOST_MATH_BUILD_MODULE #include #else import boost.math; #endif #ifndef BOOST_MATH_BUILD_MODULE #include #include #endif #include "math_unit_test.hpp" using boost::math::differentiation::finite_difference_derivative; using boost::math::differentiation::complex_step_derivative; // tol_fd bounds the finite-difference approximation error (order 1 is the // loosest at ~2*sqrt(eps)); tol_cs bounds the essentially exact complex step. template void test_spots(const char* type_name, T tol_fd, T tol_cs) { std::cout << "Testing finite_difference for type " << type_name << std::endl; // f(x) = x*x has f'(x) = 2x, so f'(3) = 6. Exercise every supported order. auto square = [](T t) { return t * t; }; CHECK_ABSOLUTE_ERROR(static_cast(6), (finite_difference_derivative(square, static_cast(3))), tol_fd); CHECK_ABSOLUTE_ERROR(static_cast(6), (finite_difference_derivative(square, static_cast(3))), tol_fd); CHECK_ABSOLUTE_ERROR(static_cast(6), (finite_difference_derivative(square, static_cast(3))), tol_fd); CHECK_ABSOLUTE_ERROR(static_cast(6), (finite_difference_derivative(square, static_cast(3))), tol_fd); CHECK_ABSOLUTE_ERROR(static_cast(6), (finite_difference_derivative(square, static_cast(3))), tol_fd); // The error-estimate output argument is populated on the default (order 6) path. T error_estimate {}; const T d {finite_difference_derivative(square, static_cast(3), &error_estimate)}; CHECK_ABSOLUTE_ERROR(static_cast(6), d, tol_fd); CHECK_GE(error_estimate, static_cast(0)); // f(x) = x*x*x has f'(x) = 3x*x, so f'(2) = 12 (via the default order). auto cube = [](T t) { return t * t * t; }; CHECK_ABSOLUTE_ERROR(static_cast(12), (finite_difference_derivative(cube, static_cast(2))), tol_fd); // A straight line f(x) = 2x + 1 has f'(x) = 2 everywhere. auto line = [](T t) { return static_cast(2) * t + static_cast(1); }; CHECK_ABSOLUTE_ERROR(static_cast(2), (finite_difference_derivative(line, static_cast(5))), tol_fd); // Complex-step differentiation is well conditioned and exact for polynomials. auto complex_square = [](std::complex z) { return z * z; }; CHECK_ABSOLUTE_ERROR(static_cast(6), complex_step_derivative(complex_square, static_cast(3)), tol_cs); auto complex_cube = [](std::complex z) { return z * z * z; }; CHECK_ABSOLUTE_ERROR(static_cast(12), complex_step_derivative(complex_cube, static_cast(2)), tol_cs); } int main() { test_spots("double", 1e-5, 1e-11); test_spots("float", 1e-2f, 1e-5f); return boost::math::test::report_errors(); }