From 05ff277ebfd5fb8d21481349456454cac0600a6b Mon Sep 17 00:00:00 2001 From: Samuel Pires <98485367+disnoca@users.noreply.github.com> Date: Fri, 2 Jun 2023 17:43:21 +0100 Subject: [PATCH] feat: add Secant Method (#1255) * feat: add secant method * Apply suggestions from code review Co-authored-by: Sharon "Cass" Cassidy * fixed indentation * added more tests * better clarification for the tolerance parameter * removed redundant comments * chore: apply suggestions from code review --------- Co-authored-by: Sharon "Cass" Cassidy Co-authored-by: scpires Co-authored-by: David Leal --- numerical_methods/secant_method.c | 80 +++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 numerical_methods/secant_method.c diff --git a/numerical_methods/secant_method.c b/numerical_methods/secant_method.c new file mode 100644 index 00000000..94628538 --- /dev/null +++ b/numerical_methods/secant_method.c @@ -0,0 +1,80 @@ +/** + * @file + * @brief [Secant Method](https://en.wikipedia.org/wiki/Secant_method) implementation. Find a + * continuous function's root by using a succession of roots of secant lines to + * approximate it, starting from the given points' secant line. + * @author [Samuel Pires](https://github.com/disnoca) + */ + +#include /// for assert +#include /// for fabs +#include /// for io operations + +#define TOLERANCE 0.0001 // root approximation result tolerance +#define NMAX 100 // maximum number of iterations + +/** + * @brief Continuous function for which we want to find the root + * @param x Real input variable + * @returns The evaluation result of the function using the input value + */ +double func(double x) +{ + return x * x - 3.; // x^2 = 3 - solution is sqrt(3) +} + +/** + * @brief Root-finding method for a continuous function given two points + * @param x0 One of the starting secant points + * @param x1 One of the starting secant points + * @param tolerance Determines how accurate the returned value is. The returned + * value will be within `tolerance` of the actual root + * @returns `root of the function` if secant method succeed within the + * maximum number of iterations + * @returns `-1` if secant method fails + */ +double secant_method(double x0, double x1, double tolerance) +{ + int n = 1; // step counter + + while (n++ < NMAX) + { + // calculate secant line root + double x2 = x1 - func(x1) * (x1 - x0) / (func(x1) - func(x0)); + + // update values + x0 = x1; + x1 = x2; + + // return value if it meets tolerance + if (fabs(x1 - x0) < tolerance) + return x2; + } + + return -1; // method failed (maximum number of steps exceeded) +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + // compares root values found by the secant method within the tolerance + assert(secant_method(0.2, 0.5, TOLERANCE) - sqrt(3) < TOLERANCE); + assert(fabs(secant_method(-2, -5, TOLERANCE)) - sqrt(3) < TOLERANCE); + assert(secant_method(-3, 2, TOLERANCE) - sqrt(3) < TOLERANCE); + assert(fabs(secant_method(1, -1.5, TOLERANCE)) - sqrt(3) < TOLERANCE); + + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +}