-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
complex_numbers.cpp
271 lines (251 loc) · 9.28 KB
/
complex_numbers.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/**
* @author tjgurwara99
* @file
*
* \brief An implementation of Complex Number as Objects
* \details A basic implementation of Complex Number field as a class with
* operators overloaded to accommodate (mathematical) field operations.
*/
#include <cassert>
#include <cmath>
#include <complex>
#include <ctime>
#include <iostream>
#include <stdexcept>
/**
* \brief Class Complex to represent complex numbers as a field.
*/
class Complex {
// The real value of the complex number
double re;
// The imaginary value of the complex number
double im;
public:
/**
* \brief Complex Constructor which initialises our complex number.
* \details
* Complex Constructor which initialises the complex number which takes
* three arguments.
* @param x If the third parameter is 'true' then this x is the absolute
* value of the complex number, if the third parameter is 'false' then this
* x is the real value of the complex number (optional).
* @param y If the third parameter is 'true' then this y is the argument of
* the complex number, if the third parameter is 'false' then this y is the
* imaginary value of the complex number (optional).
* @param is_polar 'false' by default. If we want to initialise our complex
* number using polar form then set this to true, otherwise set it to false
* to use initialiser which initialises real and imaginary values using the
* first two parameters (optional).
*/
explicit Complex(double x = 0.f, double y = 0.f, bool is_polar = false) {
if (!is_polar) {
re = x;
im = y;
return;
}
re = x * std::cos(y);
im = x * std::sin(y);
}
/**
* \brief Copy Constructor
* @param other The other number to equate our number to.
*/
Complex(const Complex &other) : re(other.real()), im(other.imag()) {}
/**
* \brief Member function to get real value of our complex number.
* Member function (getter) to access the class' re value.
*/
double real() const { return this->re; }
/**
* \brief Member function to get imaginary value of our complex number.
* Member function (getter) to access the class' im value.
*/
double imag() const { return this->im; }
/**
* \brief Member function to give the modulus of our complex number.
* Member function to which gives the absolute value (modulus) of our
* complex number
* @return \f$ \sqrt{z \bar{z}} \f$ where \f$ z \f$ is our complex
* number.
*/
double abs() const {
return std::sqrt(this->re * this->re + this->im * this->im);
}
/**
* \brief Member function to give the argument of our complex number.
* @return Argument of our Complex number in radians.
*/
double arg() const { return std::atan2(this->im, this->re); }
/**
* \brief Operator overload of '+' on Complex class.
* Operator overload to be able to add two complex numbers.
* @param other The other number that is added to the current number.
* @return result current number plus other number
*/
Complex operator+(const Complex &other) {
Complex result(this->re + other.re, this->im + other.im);
return result;
}
/**
* \brief Operator overload of '-' on Complex class.
* Operator overload to be able to subtract two complex numbers.
* @param other The other number being subtracted from the current number.
* @return result current number subtract other number
*/
Complex operator-(const Complex &other) {
Complex result(this->re - other.re, this->im - other.im);
return result;
}
/**
* \brief Operator overload of '*' on Complex class.
* Operator overload to be able to multiple two complex numbers.
* @param other The other number to multiply the current number to.
* @return result current number times other number.
*/
Complex operator*(const Complex &other) {
Complex result(this->re * other.re - this->im * other.im,
this->re * other.im + this->im * other.re);
return result;
}
/**
* \brief Operator overload of '~' on Complex class.
* Operator overload of the BITWISE NOT which gives us the conjugate of our
* complex number. NOTE: This is overloading the BITWISE operator but its
* not a BITWISE operation in this definition.
* @return result The conjugate of our complex number.
*/
Complex operator~() const {
Complex result(this->re, -(this->im));
return result;
}
/**
* \brief Operator overload of '/' on Complex class.
* Operator overload to be able to divide two complex numbers. This function
* would throw an exception if the other number is zero.
* @param other The other number we divide our number by.
* @return result Current number divided by other number.
*/
Complex operator/(const Complex &other) {
Complex result = *this * ~other;
double denominator =
other.real() * other.real() + other.imag() * other.imag();
if (denominator != 0) {
result = Complex(result.real() / denominator,
result.imag() / denominator);
return result;
} else {
throw std::invalid_argument("Undefined Value");
}
}
/**
* \brief Operator overload of '=' on Complex class.
* Operator overload to be able to copy RHS instance of Complex to LHS
* instance of Complex
*/
const Complex &operator=(const Complex &other) {
this->re = other.real();
this->im = other.imag();
return *this;
}
};
/**
* \brief Operator overload of '==' on Complex class.
* Logical Equal overload for our Complex class.
* @param a Left hand side of our expression
* @param b Right hand side of our expression
* @return 'True' If real and imaginary parts of a and b are same
* @return 'False' Otherwise.
*/
bool operator==(const Complex &a, const Complex &b) {
return a.real() == b.real() && a.imag() == b.imag();
}
/**
* \brief Operator overload of '<<' of ostream for Complex class.
* Overloaded insersion operator to accommodate the printing of our complex
* number in their standard form.
* @param os The console stream
* @param num The complex number.
*/
std::ostream &operator<<(std::ostream &os, const Complex &num) {
os << "(" << num.real();
if (num.imag() < 0) {
os << " - " << -num.imag();
} else {
os << " + " << num.imag();
}
os << "i)";
return os;
}
/**
* \brief Function to get random numbers to generate our complex numbers for
* test
*/
double get_rand() { return (std::rand() % 100 - 50) / 100.f; }
/**
* Tests Function
*/
void tests() {
std::srand(std::time(nullptr));
double x1 = get_rand(), y1 = get_rand(), x2 = get_rand(), y2 = get_rand();
Complex num1(x1, y1), num2(x2, y2);
std::complex<double> cnum1(x1, y1), cnum2(x2, y2);
Complex result;
std::complex<double> expected;
// Test for addition
result = num1 + num2;
expected = cnum1 + cnum2;
assert(((void)"1 + 1i + 1 + 1i is equal to 2 + 2i but the addition doesn't "
"add up \n",
(result.real() == expected.real() &&
result.imag() == expected.imag())));
std::cout << "First test passes." << std::endl;
// Test for subtraction
result = num1 - num2;
expected = cnum1 - cnum2;
assert(((void)"1 + 1i - 1 - 1i is equal to 0 but the program says "
"otherwise. \n",
(result.real() == expected.real() &&
result.imag() == expected.imag())));
std::cout << "Second test passes." << std::endl;
// Test for multiplication
result = num1 * num2;
expected = cnum1 * cnum2;
assert(((void)"(1 + 1i) * (1 + 1i) is equal to 2i but the program says "
"otherwise. \n",
(result.real() == expected.real() &&
result.imag() == expected.imag())));
std::cout << "Third test passes." << std::endl;
// Test for division
result = num1 / num2;
expected = cnum1 / cnum2;
assert(((void)"(1 + 1i) / (1 + 1i) is equal to 1 but the program says "
"otherwise.\n",
(result.real() == expected.real() &&
result.imag() == expected.imag())));
std::cout << "Fourth test passes." << std::endl;
// Test for conjugates
result = ~num1;
expected = std::conj(cnum1);
assert(((void)"(1 + 1i) has a conjugate which is equal to (1 - 1i) but the "
"program says otherwise.\n",
(result.real() == expected.real() &&
result.imag() == expected.imag())));
std::cout << "Fifth test passes.\n";
// Test for Argument of our complex number
assert(((void)"(1 + 1i) has argument PI / 4 but the program differs from "
"the std::complex result.\n",
(num1.arg() == std::arg(cnum1))));
std::cout << "Sixth test passes.\n";
// Test for absolute value of our complex number
assert(((void)"(1 + 1i) has absolute value sqrt(2) but the program differs "
"from the std::complex result. \n",
(num1.abs() == std::abs(cnum1))));
std::cout << "Seventh test passes.\n";
}
/**
* Main function
*/
int main() {
tests();
return 0;
}