|
| 1 | +/** |
| 2 | + * @file |
| 3 | + * @brief [Secant Method](https://en.wikipedia.org/wiki/Secant_method) implementation. Find a |
| 4 | + * continuous function's root by using a succession of roots of secant lines to |
| 5 | + * approximate it, starting from the given points' secant line. |
| 6 | + * @author [Samuel Pires](https://github.com/disnoca) |
| 7 | + */ |
| 8 | + |
| 9 | +#include <assert.h> /// for assert |
| 10 | +#include <math.h> /// for fabs |
| 11 | +#include <stdio.h> /// for io operations |
| 12 | + |
| 13 | +#define TOLERANCE 0.0001 // root approximation result tolerance |
| 14 | +#define NMAX 100 // maximum number of iterations |
| 15 | + |
| 16 | +/** |
| 17 | + * @brief Continuous function for which we want to find the root |
| 18 | + * @param x Real input variable |
| 19 | + * @returns The evaluation result of the function using the input value |
| 20 | + */ |
| 21 | +double func(double x) |
| 22 | +{ |
| 23 | + return x * x - 3.; // x^2 = 3 - solution is sqrt(3) |
| 24 | +} |
| 25 | + |
| 26 | +/** |
| 27 | + * @brief Root-finding method for a continuous function given two points |
| 28 | + * @param x0 One of the starting secant points |
| 29 | + * @param x1 One of the starting secant points |
| 30 | + * @param tolerance Determines how accurate the returned value is. The returned |
| 31 | + * value will be within `tolerance` of the actual root |
| 32 | + * @returns `root of the function` if secant method succeed within the |
| 33 | + * maximum number of iterations |
| 34 | + * @returns `-1` if secant method fails |
| 35 | + */ |
| 36 | +double secant_method(double x0, double x1, double tolerance) |
| 37 | +{ |
| 38 | + int n = 1; // step counter |
| 39 | + |
| 40 | + while (n++ < NMAX) |
| 41 | + { |
| 42 | + // calculate secant line root |
| 43 | + double x2 = x1 - func(x1) * (x1 - x0) / (func(x1) - func(x0)); |
| 44 | + |
| 45 | + // update values |
| 46 | + x0 = x1; |
| 47 | + x1 = x2; |
| 48 | + |
| 49 | + // return value if it meets tolerance |
| 50 | + if (fabs(x1 - x0) < tolerance) |
| 51 | + return x2; |
| 52 | + } |
| 53 | + |
| 54 | + return -1; // method failed (maximum number of steps exceeded) |
| 55 | +} |
| 56 | + |
| 57 | +/** |
| 58 | + * @brief Self-test implementations |
| 59 | + * @returns void |
| 60 | + */ |
| 61 | +static void test() |
| 62 | +{ |
| 63 | + // compares root values found by the secant method within the tolerance |
| 64 | + assert(secant_method(0.2, 0.5, TOLERANCE) - sqrt(3) < TOLERANCE); |
| 65 | + assert(fabs(secant_method(-2, -5, TOLERANCE)) - sqrt(3) < TOLERANCE); |
| 66 | + assert(secant_method(-3, 2, TOLERANCE) - sqrt(3) < TOLERANCE); |
| 67 | + assert(fabs(secant_method(1, -1.5, TOLERANCE)) - sqrt(3) < TOLERANCE); |
| 68 | + |
| 69 | + printf("All tests have successfully passed!\n"); |
| 70 | +} |
| 71 | + |
| 72 | +/** |
| 73 | + * @brief Main function |
| 74 | + * @returns 0 on exit |
| 75 | + */ |
| 76 | +int main() |
| 77 | +{ |
| 78 | + test(); // run self-test implementations |
| 79 | + return 0; |
| 80 | +} |
0 commit comments