diff --git a/data_structures/segment_tree.cpp b/data_structures/segment_tree.cpp new file mode 100755 index 00000000000..71d85f0b1a5 --- /dev/null +++ b/data_structures/segment_tree.cpp @@ -0,0 +1,133 @@ +/** + * @file + * @brief A data structure to quickly do operations on ranges: the [Segment Tree](https://en.wikipedia.org/wiki/Segment_tree) algorithm implementation + * @details + * Implementation of the segment tree data structre + * + * Can do point updates (updates the value of some position) + * and range queries, where it gives the value of some associative + * opperation done on a range + * + * Both of these operations take O(log N) time + * @author [Nishant Chatterjee](https://github.com/nishantc1527) + */ + +#include /// For IO operations +#include /// For std::vector +#include /// For std::min and std::max +#include /// For assert + +/* + * @namespace + * @brief Data structures + */ +namespace data_structures { +/** + * @brief class representation of the segment tree + * @tparam T The type of the class that goes in the datastructure + */ +template +class SegmentTree { +private: + const T ID = 0; ///< Comb(ID, x) = x + std::vector t; ///< Vector to represent the tree + int size = 0; ///< Number of elements available for querying in the tree +private: + /** + * @brief Any associative function that combines x and y + * @param x The first operand + * @param y The second operand + * @return Some associative operation applied to these two values. In this case, I used addition + */ + T comb(T x, T y) { + return x + y; + } + /** + * @brief Gives the midpoint between two integers + * @param l The left endpoint + * @param r The right endpoint + * @return the middle point between them + */ + int mid(int l, int r) { + return l + (r - l) / 2; + } + /** + * @brief Helper method for update method below + * @param i The index of the current node + * @param l The leftmost node of the current node + * @param r The rightmost node of the current node + * @param pos The position to update + * @param val The value to update it to + */ + void update(int i, int l, int r, int pos, T val) { + if(l == r) t[i] = val; + else { + int m = mid(l, r); + if(pos <= m) update(i * 2, l, m, pos, val); + else update(i * 2 + 1, m + 1, r, pos, val); + t[i] = comb(t[i * 2], t[i * 2 + 1]); + } + } + /** + * @brief Helper method for range_comb method below + * @param i The current node + * @param l The leftmost node of the current node + * @param r The rightmost node of the current node + * @param tl The left endpoint of the range + * @param tr The right endpoint of the range + * @return The comb operation applied to all values between tl and tr + */ + T range_comb(int i, int l, int r, int tl, int tr) { + if(l == tl && r == tr) return t[i]; + if(tl > tr) return 0; + int m = mid(l, r); + return comb(range_comb(i * 2, l, m, tl, std::min(tr, m)), range_comb(i * 2 + 1, m + 1, r, std::max(tl, m + 1), tr)); + } +public: + SegmentTree(int n) : t(n * 4, ID), size(n) {} + /** + * @brief Updates a value at a certain position + * @param pos The position to update + * @param val The value to update it to + */ + void update(int pos, T val) { + update(1, 1, size, pos, val); + } + /** + * @brief Returns comb across all values between l and r + * @param l The left endpoint of the range + * @param r The right endpoint of the range + * @return The value of the comb operations + */ + T range_comb(int l, int r) { + return range_comb(1, 1, size, l, r); + } +}; +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + data_structures::SegmentTree t(5); + t.update(1, 1); + t.update(2, 2); + t.update(3, 3); + t.update(4, 4); + t.update(5, 5); + assert(t.range_comb(1, 3) == 6); // 1 + 2 + 3 = 6 + t.update(1, 3); + assert(t.range_comb(1, 3) == 8); // 3 + 2 + 3 = 8 + + std::cout << "All tests have successfully passed!\n"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/math/eulers_totient_function.cpp b/math/eulers_totient_function.cpp index 8283ab04503..f1752e9e92a 100644 --- a/math/eulers_totient_function.cpp +++ b/math/eulers_totient_function.cpp @@ -1,9 +1,7 @@ /** * @file - * @brief C++ Program to find - * [Euler's Totient](https://en.wikipedia.org/wiki/Euler%27s_totient_function) - * function - * + * @brief Implementation of [Euler's Totient](https://en.wikipedia.org/wiki/Euler%27s_totient_function) + * @description * Euler Totient Function is also known as phi function. * \f[\phi(n) = * \phi\left({p_1}^{a_1}\right)\cdot\phi\left({p_2}^{a_2}\right)\ldots\f] where @@ -23,36 +21,58 @@ * * \f$\phi(1) = 1\f$ * * \f$\phi(17501) = 15120\f$ * * \f$\phi(1420) = 560\f$ + * @author [Mann Mehta](https://github.com/mann2108) */ -#include -#include -/** Function to caculate Euler's totient phi +#include /// for IO operations +#include /// for assert + +/** + * @brief Mathematical algorithms + * @namespace + */ +namespace math { +/** + * @brief Function to calculate Euler's Totient + * @param n the number to find the Euler's Totient of */ uint64_t phiFunction(uint64_t n) { uint64_t result = n; for (uint64_t i = 2; i * i <= n; i++) { - if (n % i == 0) { - while (n % i == 0) { - n /= i; - } - result -= result / i; - } + if (n % i != 0) continue; + while (n % i == 0) n /= i; + + result -= result / i; } - if (n > 1) - result -= result / n; + if (n > 1) result -= result / n; + return result; } +} // namespace math -/// Main function +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + assert(math::phiFunction(1) == 1); + assert(math::phiFunction(2) == 1); + assert(math::phiFunction(10) == 4); + assert(math::phiFunction(123456) == 41088); + assert(math::phiFunction(808017424794) == 263582333856); + assert(math::phiFunction(3141592) == 1570792); + assert(math::phiFunction(27182818) == 12545904); + + std::cout << "All tests have successfully passed!\n"; +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ int main(int argc, char *argv[]) { - uint64_t n; - if (argc < 2) { - std::cout << "Enter the number: "; - } else { - n = strtoull(argv[1], nullptr, 10); - } - std::cin >> n; - std::cout << phiFunction(n); + test(); return 0; } diff --git a/math/quadratic_equations_complex_numbers.cpp b/math/quadratic_equations_complex_numbers.cpp new file mode 100644 index 00000000000..3a50719e5dc --- /dev/null +++ b/math/quadratic_equations_complex_numbers.cpp @@ -0,0 +1,189 @@ +/** + * @file + * @brief Calculate quadratic equation with complex roots, i.e. b^2 - 4ac < 0. + * + * @author [Renjian-buchai](https://github.com/Renjian-buchai) + * + * @description Calculates any quadratic equation in form ax^2 + bx + c. + * + * Quadratic equation: + * x = (-b +/- sqrt(b^2 - 4ac)) / 2a + * + * @example + * int main() { + * using std::array; + * using std::complex; + * using std::cout; + * + * array solutions = quadraticEquation(1, 2, 1); + * cout << solutions[0] << " " << solutions[1] << "\n"; + * + * solutions = quadraticEquation(1, 1, 1); // Reusing solutions. + * cout << solutions[0] << " " << solutions[1] << "\n"; + * return 0; + * } + * + * Output: + * (-1, 0) (-1, 0) + * (-0.5,0.866025) (-0.5,0.866025) + */ + +#include /// std::array +#include /// assert +#include /// std::sqrt, std::trunc, std::pow +#include /// std::complex +#include /// std::invalid_argument +#include /// std::setprecision +#include /// std::cout + +/** + * @namespace + * @brief Mathematical algorithms + */ +namespace math { + +/** + * @brief Quadratic equation calculator. + * @param a quadratic coefficient. + * @param b linear coefficient. + * @param c constant + * @return Array containing the roots of quadratic equation, incl. complex + * root. + */ +std::array, 2> quadraticEquation(long double a, + long double b, + long double c) { + if (a == 0) { + throw std::invalid_argument("quadratic coefficient cannot be 0"); + } + + long double discriminant = b * b - 4 * a * c; + std::array, 2> solutions{0, 0}; + + if (discriminant == 0) { + solutions[0] = -b * 0.5 / a; + solutions[1] = -b * 0.5 / a; + return solutions; + } + + // Complex root (discriminant < 0) + // Note that the left term (-b / 2a) is always real. The imaginary part + // appears when b^2 - 4ac < 0, so sqrt(b^2 - 4ac) has no real roots. So, + // the imaginary component is i * (+/-)sqrt(abs(b^2 - 4ac)) / 2a. + if (discriminant > 0) { + // Since discriminant > 0, there are only real roots. Therefore, + // imaginary component = 0. + solutions[0] = std::complex{ + (-b - std::sqrt(discriminant)) * 0.5 / a, 0}; + solutions[1] = std::complex{ + (-b + std::sqrt(discriminant)) * 0.5 / a, 0}; + return solutions; + } + // Since b^2 - 4ac is < 0, for faster computation, -discriminant is + // enough to make it positive. + solutions[0] = std::complex{ + -b * 0.5 / a, -std::sqrt(-discriminant) * 0.5 / a}; + solutions[1] = std::complex{ + -b * 0.5 / a, std::sqrt(-discriminant) * 0.5 / a}; + + return solutions; +} + +} // namespace math + +/** + * @brief Asserts an array of complex numbers. + * @param input Input array of complex numbers. . + * @param expected Expected array of complex numbers. + * @param precision Precision to be asserted. Default=10 + */ +void assertArray(std::array, 2> input, + std::array, 2> expected, + size_t precision = 10) { + long double exponent = std::pow(10, precision); + input[0].real(std::round(input[0].real() * exponent)); + input[1].real(std::round(input[1].real() * exponent)); + input[0].imag(std::round(input[0].imag() * exponent)); + input[1].imag(std::round(input[1].imag() * exponent)); + + expected[0].real(std::round(expected[0].real() * exponent)); + expected[1].real(std::round(expected[1].real() * exponent)); + expected[0].imag(std::round(expected[0].imag() * exponent)); + expected[1].imag(std::round(expected[1].imag() * exponent)); + + assert(input == expected); +} + +/** + * @brief Self-test implementations to test quadraticEquation function. + * @note There are 4 different types of solutions: Real and equal, real, + * complex, complex and equal. + */ +static void test() { + // Values are equal and real. + std::cout << "Input: \n" + "a=1 \n" + "b=-2 \n" + "c=1 \n" + "Expected output: \n" + "(1, 0), (1, 0)\n\n"; + std::array, 2> equalCase{ + std::complex{1, 0}, std::complex{1, 0}}; + assert(math::quadraticEquation(1, -2, 1) == equalCase); + + // Values are equal and complex. + std::cout << "Input: \n" + "a=1 \n" + "b=4 \n" + "c=5 \n" + "Expected output: \n" + "(-2, -1), (-2, 1)\n\n"; + std::array, 2> complexCase{ + std::complex{-2, -1}, std::complex{-2, 1}}; + assert(math::quadraticEquation(1, 4, 5) == complexCase); + + // Values are real. + std::cout << "Input: \n" + "a=1 \n" + "b=5 \n" + "c=1 \n" + "Expected output: \n" + "(-4.7912878475, 0), (-0.2087121525, 0)\n\n"; + std::array, 2> floatCase{ + std::complex{-4.7912878475, 0}, + std::complex{-0.2087121525, 0}}; + assertArray(math::quadraticEquation(1, 5, 1), floatCase); + + // Values are complex. + std::cout << "Input: \n" + "a=1 \n" + "b=1 \n" + "c=1 \n" + "Expected output: \n" + "(-0.5, -0.8660254038), (-0.5, 0.8660254038)\n\n"; + std::array, 2> ifloatCase{ + std::complex{-0.5, -0.8660254038}, + std::complex{-0.5, 0.8660254038}}; + assertArray(math::quadraticEquation(1, 1, 1), ifloatCase); + + std::cout << "Exception test: \n" + "Input: \n" + "a=0 \n" + "b=0 \n" + "c=0\n" + "Expected output: Exception thrown \n"; + try { + math::quadraticEquation(0, 0, 0); + } catch (std::invalid_argument& e) { + std::cout << "Exception thrown successfully \n"; + } +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // Run self-test implementation. + return 0; +}