diff --git a/math/bisection_method.cpp b/math/bisection_method.cpp index 6f7ad28df..794d7927f 100644 --- a/math/bisection_method.cpp +++ b/math/bisection_method.cpp @@ -1,43 +1,101 @@ -#include -#include -using namespace std; +/** + * @file + * @brief Program to find the roots of a conitnuous function for which two values + * with opposite signs are known (https://en.wikipedia.org/wiki/Bisection_method) + * + * @details + * The method is applicable for numerically solving the equation f(x) = 0 + * for the real variable x, where f is a continuous function + * defined on an interval [a, b] and where f(a) and f(b) have opposite signs. + * + * let the function f(x) be any continuous function such that f(a)*f(b) < 0 + * this method takes the mid value of 'a' and 'b' [mid = (a+b)/2] and then + * check if f(mid) = 0, + * if not, then it recursively calls itself with intervals [a, mid] and [mid, b] + * until the middle value of the provided interval is equal to 0 + * (or the difference in the value of interval is < the permissible error) + * [the condition in the above bracket is taken bcoz if the interval are so close + * then the approximate root of the equation is around the mid value of them] + * + * @author [Kush Choudhary](https://github.com/kushchoudhary98) + */ +#include ///for assert +#include ///for IO operations +#include ///for math operations -double f(double x) {//can add your own function +/** + * @brief The function f(x) whose root is to be known + * @param x value to be evaluated in function `f` + * @return the evaluated value of funtion `f` through x +*/ +double f(double x) { return cos(x) - x*exp(x); } -void bisection(double x, double y, double error = 0.00001) { - static bool flag = false;//to make sure the 'invalid interval' message is printed correctly - if(f(x)*f(y) >= 0) { - if(flag == false) cout << "The interval [a,b] provided is not valid" << endl; - return; +/** + * @brief Function to get the root of the function `f` + * @param a first known value + * @param b second known value + * @param error permissible error in calculation + * @return Returns the value of the root of the function `f`. + * @return Returns `-1` and a message if interval [a,b] is invalid and/or the function does not follow the required assumptions. +*/ +double bisection(double a, double b, double error = 0.00001) { + static bool flag = false; + + //if f(a)*f(b) < 0, then interval [a, b] is invalid + if(f(a)*f(b) >= 0) { + if(flag == false) std::cout << "The interval [a,b] provided is not valid returning value -1" << std::endl; + return -1; } flag = true; - double z = (x+y)/2; - if(abs(x-y) <= error) { - cout << "The approximate root is : " << z << endl; - return; + double z = (a+b)/2; + + //if difference in interval is less than the `error` then return + //the mid as answer + if(abs(a-b) <= error) { + return z; } + //if f(mid) = 0, then mid is the root if(f(z) == 0.0) { - cout << "The root is : " << z << endl; - return; + return z; } else { - if(f(x)*f(z) < 0) bisection(x, z, error); - else if(f(z)*f(y) < 0) bisection(y, z, error); + //recursively calling the method with interval [a, mid] + if(f(a)*f(z) < 0) return bisection(a, z, error); + + //recursively calling the method with interval [mid, b] + else if(f(z)*f(b) < 0) return bisection(b, z, error); + else { - cout << "The given function does not follow the required assumtions" << endl; - return; + std::cout << "The given function does not follow the required assumtions, returning -1" << std::endl; + return -1; } } + return z; } +/** + * @brief Self-test implementations + * @returns void + */ +void test() { + double ans = bisection(0,1); + ans = (std::ceil(ans * 100000))/100000;//to round upto 5 decimal places + + assert(ans == 0.51776); + + std::cout << "All tests have successfully passed!\n"; +} + + +/** + * @brief Main Function + * @returns 0 on exit + */ int main(void) { - double a, b; - cout << "Enter the two guesses : " << endl; - cin >> a; - cin >> b; - bisection(a, b); -} \ No newline at end of file + test(); //runs self-test implementation + return 0; +}