From 75a845f44ff7b4d5da080d7d1492c335dcb0014b Mon Sep 17 00:00:00 2001 From: infinage <37257700+Infinage@users.noreply.github.com> Date: Mon, 14 Apr 2025 19:19:51 +0530 Subject: [PATCH] test/docs: math/sqrt_double.cpp docs & tests --- math/sqrt_double.cpp | 109 +++++++++++++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/math/sqrt_double.cpp b/math/sqrt_double.cpp index c4beec9d8c6..741433d33bc 100644 --- a/math/sqrt_double.cpp +++ b/math/sqrt_double.cpp @@ -1,49 +1,88 @@ /** * @file - * @brief Calculate the square root of any positive real number in \f$O(\log - * N)\f$ time, with precision fixed using [bisection - * method](https://en.wikipedia.org/wiki/Bisection_method) of root-finding. + * @brief Computes square root of a positive real number using the bisection method. * - * @see Can be implemented using faster and better algorithms like - * newton_raphson_method.cpp and false_position.cpp + * @details + * This implementation solves the equation \f$x^2 = a\f$ using binary search. + * Only the positive root is returned. Time complexity is \f$O(\log N)\f$. + * + * @note + * Can be implemented using faster and better algorithms like: + * - numerical_methods/newton_raphson_method.cpp + * - numerical_methods/false_position.cpp */ #include -#include +#include -/** Bisection method implemented for the function \f$x^2-a=0\f$ - * whose roots are \f$\pm\sqrt{a}\f$ and only the positive root is returned. +/** + * @brief Mathematical algorithms + * @namespace */ -double Sqrt(double a) { - if (a > 0 && a < 1) { - return 1 / Sqrt(1 / a); - } - double l = 0, r = a; - /* Epsilon is the precision. - A great precision is - between 1e-7 and 1e-12. - double epsilon = 1e-12; - */ - double epsilon = 1e-12; - while (l <= r) { - double mid = (l + r) / 2; - if (mid * mid > a) { - r = mid; - } else { - if (a - mid * mid < epsilon) { +namespace math { + /** + * @brief Bisection method implemented for the function \f$x^2-a=0\f$ + * whose roots are \f$\pm\sqrt{a}\f$ and only the positive root is returned. + * @param num Number to find the square root for + * @param eps Determines the output precision. A good value lies between 1e-7 to 1e-12 + * @returns Square root of input + */ + double Sqrt(double num, double eps = 1e-12) { + // Error: Sqrt for neg numbers is not defined + if (num < 0) return -1; + + // Handling floats that are 0 < x <= 1 + // (1 / sqrt(1 / num)) is same as sqrt(num) + if ( 0 < num && num < 1 ) + return 1 / Sqrt(1 / num, eps); + + // Binary search to find the value whose + // square is equal to or off the target by + // utmost eps + double low = 0, high = num; + while (low <= high) { + double mid = (low + high) / 2; + double sq = mid * mid; + if (sq <= num && sq >= num - eps) return mid; - } - l = mid; + else if (sq > num) + high = mid; + else + low = mid; } + + return -1; } - return -1; +} // namespace math + +/** + * @brief Self-test implementations + * @returns void + */ +void test() { + // eps = 1e-12 + assert(std::format("{:.12f}", math::Sqrt( 2)) == "1.414213562373"); + assert(std::format("{:.12f}", math::Sqrt( 17)) == "4.123105625618"); + assert(std::format("{:.12f}", math::Sqrt( 49)) == "7.000000000000"); + assert(std::format("{:.12f}", math::Sqrt( 311)) == "17.635192088548"); + assert(std::format("{:.12f}", math::Sqrt(0.42)) == "0.648074069841"); + assert(std::format("{:.12f}", math::Sqrt(0.11)) == "0.331662479036"); + assert(std::format("{:.12f}", math::Sqrt(0.03)) == "0.173205080757"); + + // eps = 1e-8 + assert(std::format("{:.8f}", math::Sqrt( 2, 1e-8)) == "1.41421356"); + assert(std::format("{:.8f}", math::Sqrt( 17, 1e-8)) == "4.12310563"); + assert(std::format("{:.8f}", math::Sqrt( 49, 1e-8)) == "7.00000000"); + assert(std::format("{:.8f}", math::Sqrt( 311, 1e-8)) == "17.63519209"); + assert(std::format("{:.8f}", math::Sqrt(0.42, 1e-8)) == "0.64807407"); + assert(std::format("{:.8f}", math::Sqrt(0.11, 1e-8)) == "0.33166248"); + assert(std::format("{:.8f}", math::Sqrt(0.03, 1e-8)) == "0.17320508"); } -/** main function */ +/** + * @brief Main Function + * @returns 0 on exit + */ int main() { - double n{}; - std::cin >> n; - assert(n >= 0); - // Change this line for a better precision - std::cout.precision(12); - std::cout << std::fixed << Sqrt(n); + test(); + return 0; }