Skip to content

Commit a022701

Browse files
Renjian-buchaiPanquesito7realstealthninjatjgurwara99
authored
feat: add Quadratic equations complex numbers (#2451)
* Added quadratic_equations_complex_numbers.cpp * Added a demonstration * Added test cases * Added test cases * Revert "Added test cases" This reverts commit a1433a9. * Added test cases and made docs /// instead of // * test: Added test cases for quadraticEquation docs: Changed comment style * test: more test cases docs: added documentation * docs: Updated description * chore: removed redundant returns * chore: fixed formatting to pass Code Formatter checks * chore: apply suggestions from code review Co-authored-by: realstealthninja <[email protected]> * test: Added exception test * Update math/quadratic_equations_complex_numbers.cpp Co-authored-by: Taj <[email protected]> * Update math/quadratic_equations_complex_numbers.cpp Co-authored-by: Taj <[email protected]> * Update math/quadratic_equations_complex_numbers.cpp Co-authored-by: Taj <[email protected]> --------- Co-authored-by: David Leal <[email protected]> Co-authored-by: realstealthninja <[email protected]> Co-authored-by: Taj <[email protected]>
1 parent 1a1570d commit a022701

File tree

1 file changed

+189
-0
lines changed

1 file changed

+189
-0
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/**
2+
* @file
3+
* @brief Calculate quadratic equation with complex roots, i.e. b^2 - 4ac < 0.
4+
*
5+
* @author [Renjian-buchai](https://github.com/Renjian-buchai)
6+
*
7+
* @description Calculates any quadratic equation in form ax^2 + bx + c.
8+
*
9+
* Quadratic equation:
10+
* x = (-b +/- sqrt(b^2 - 4ac)) / 2a
11+
*
12+
* @example
13+
* int main() {
14+
* using std::array;
15+
* using std::complex;
16+
* using std::cout;
17+
*
18+
* array<complex<long double, 2> solutions = quadraticEquation(1, 2, 1);
19+
* cout << solutions[0] << " " << solutions[1] << "\n";
20+
*
21+
* solutions = quadraticEquation(1, 1, 1); // Reusing solutions.
22+
* cout << solutions[0] << " " << solutions[1] << "\n";
23+
* return 0;
24+
* }
25+
*
26+
* Output:
27+
* (-1, 0) (-1, 0)
28+
* (-0.5,0.866025) (-0.5,0.866025)
29+
*/
30+
31+
#include <array> /// std::array
32+
#include <cassert> /// assert
33+
#include <cmath> /// std::sqrt, std::trunc, std::pow
34+
#include <complex> /// std::complex
35+
#include <exception> /// std::invalid_argument
36+
#include <iomanip> /// std::setprecision
37+
#include <iostream> /// std::cout
38+
39+
/**
40+
* @namespace
41+
* @brief Mathematical algorithms
42+
*/
43+
namespace math {
44+
45+
/**
46+
* @brief Quadratic equation calculator.
47+
* @param a quadratic coefficient.
48+
* @param b linear coefficient.
49+
* @param c constant
50+
* @return Array containing the roots of quadratic equation, incl. complex
51+
* root.
52+
*/
53+
std::array<std::complex<long double>, 2> quadraticEquation(long double a,
54+
long double b,
55+
long double c) {
56+
if (a == 0) {
57+
throw std::invalid_argument("quadratic coefficient cannot be 0");
58+
}
59+
60+
long double discriminant = b * b - 4 * a * c;
61+
std::array<std::complex<long double>, 2> solutions{0, 0};
62+
63+
if (discriminant == 0) {
64+
solutions[0] = -b * 0.5 / a;
65+
solutions[1] = -b * 0.5 / a;
66+
return solutions;
67+
}
68+
69+
// Complex root (discriminant < 0)
70+
// Note that the left term (-b / 2a) is always real. The imaginary part
71+
// appears when b^2 - 4ac < 0, so sqrt(b^2 - 4ac) has no real roots. So,
72+
// the imaginary component is i * (+/-)sqrt(abs(b^2 - 4ac)) / 2a.
73+
if (discriminant > 0) {
74+
// Since discriminant > 0, there are only real roots. Therefore,
75+
// imaginary component = 0.
76+
solutions[0] = std::complex<long double>{
77+
(-b - std::sqrt(discriminant)) * 0.5 / a, 0};
78+
solutions[1] = std::complex<long double>{
79+
(-b + std::sqrt(discriminant)) * 0.5 / a, 0};
80+
return solutions;
81+
}
82+
// Since b^2 - 4ac is < 0, for faster computation, -discriminant is
83+
// enough to make it positive.
84+
solutions[0] = std::complex<long double>{
85+
-b * 0.5 / a, -std::sqrt(-discriminant) * 0.5 / a};
86+
solutions[1] = std::complex<long double>{
87+
-b * 0.5 / a, std::sqrt(-discriminant) * 0.5 / a};
88+
89+
return solutions;
90+
}
91+
92+
} // namespace math
93+
94+
/**
95+
* @brief Asserts an array of complex numbers.
96+
* @param input Input array of complex numbers. .
97+
* @param expected Expected array of complex numbers.
98+
* @param precision Precision to be asserted. Default=10
99+
*/
100+
void assertArray(std::array<std::complex<long double>, 2> input,
101+
std::array<std::complex<long double>, 2> expected,
102+
size_t precision = 10) {
103+
long double exponent = std::pow(10, precision);
104+
input[0].real(std::round(input[0].real() * exponent));
105+
input[1].real(std::round(input[1].real() * exponent));
106+
input[0].imag(std::round(input[0].imag() * exponent));
107+
input[1].imag(std::round(input[1].imag() * exponent));
108+
109+
expected[0].real(std::round(expected[0].real() * exponent));
110+
expected[1].real(std::round(expected[1].real() * exponent));
111+
expected[0].imag(std::round(expected[0].imag() * exponent));
112+
expected[1].imag(std::round(expected[1].imag() * exponent));
113+
114+
assert(input == expected);
115+
}
116+
117+
/**
118+
* @brief Self-test implementations to test quadraticEquation function.
119+
* @note There are 4 different types of solutions: Real and equal, real,
120+
* complex, complex and equal.
121+
*/
122+
static void test() {
123+
// Values are equal and real.
124+
std::cout << "Input: \n"
125+
"a=1 \n"
126+
"b=-2 \n"
127+
"c=1 \n"
128+
"Expected output: \n"
129+
"(1, 0), (1, 0)\n\n";
130+
std::array<std::complex<long double>, 2> equalCase{
131+
std::complex<long double>{1, 0}, std::complex<long double>{1, 0}};
132+
assert(math::quadraticEquation(1, -2, 1) == equalCase);
133+
134+
// Values are equal and complex.
135+
std::cout << "Input: \n"
136+
"a=1 \n"
137+
"b=4 \n"
138+
"c=5 \n"
139+
"Expected output: \n"
140+
"(-2, -1), (-2, 1)\n\n";
141+
std::array<std::complex<long double>, 2> complexCase{
142+
std::complex<long double>{-2, -1}, std::complex<long double>{-2, 1}};
143+
assert(math::quadraticEquation(1, 4, 5) == complexCase);
144+
145+
// Values are real.
146+
std::cout << "Input: \n"
147+
"a=1 \n"
148+
"b=5 \n"
149+
"c=1 \n"
150+
"Expected output: \n"
151+
"(-4.7912878475, 0), (-0.2087121525, 0)\n\n";
152+
std::array<std::complex<long double>, 2> floatCase{
153+
std::complex<long double>{-4.7912878475, 0},
154+
std::complex<long double>{-0.2087121525, 0}};
155+
assertArray(math::quadraticEquation(1, 5, 1), floatCase);
156+
157+
// Values are complex.
158+
std::cout << "Input: \n"
159+
"a=1 \n"
160+
"b=1 \n"
161+
"c=1 \n"
162+
"Expected output: \n"
163+
"(-0.5, -0.8660254038), (-0.5, 0.8660254038)\n\n";
164+
std::array<std::complex<long double>, 2> ifloatCase{
165+
std::complex<long double>{-0.5, -0.8660254038},
166+
std::complex<long double>{-0.5, 0.8660254038}};
167+
assertArray(math::quadraticEquation(1, 1, 1), ifloatCase);
168+
169+
std::cout << "Exception test: \n"
170+
"Input: \n"
171+
"a=0 \n"
172+
"b=0 \n"
173+
"c=0\n"
174+
"Expected output: Exception thrown \n";
175+
try {
176+
math::quadraticEquation(0, 0, 0);
177+
} catch (std::invalid_argument& e) {
178+
std::cout << "Exception thrown successfully \n";
179+
}
180+
}
181+
182+
/**
183+
* @brief Main function
184+
* @returns 0 on exit
185+
*/
186+
int main() {
187+
test(); // Run self-test implementation.
188+
return 0;
189+
}

0 commit comments

Comments
 (0)