ccmath/lib.rs
1/// CCMath: a crate for doing math with complex numbers
2use num_traits::Float;
3use std::fmt::{Debug, Display, Formatter, Result};
4
5/// Struct representing a complex number
6#[derive(Debug, PartialEq, Clone, Copy)]
7pub struct Complex<T: Float> {
8 real: T,
9 imag: T,
10}
11
12/// Alias for [`Complex`]
13pub type CC<T> = Complex<T>;
14// Personal tip: use this alias when code is getting a little hard to read, it cleans things up!
15
16trait Numbers: Float {
17 fn two() -> Self;
18}
19
20impl<T: Float> Numbers for T {
21 /// Returns the number two
22 fn two() -> T {
23 T::one() + T::one()
24 }
25}
26
27impl<T: Float> Complex<T> {
28 /// Creates a new [`Complex`].
29 pub fn new(real: T, imag: T) -> Self {
30 Self { real, imag }
31 }
32
33 /// Returns the imaginary number i
34 pub fn i() -> Self {
35 Self::new(T::zero(), T::one())
36 }
37
38 /// Returns the real part of this [`Complex`].
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// use ccmath::Complex;
44 ///
45 /// let z = Complex::new(-1.4, 21.6);
46 /// assert_eq!(z.real(), -1.4);
47 /// ```
48 pub fn real(self) -> T {
49 self.real
50 }
51
52 /// Returns the imaginary part of this [`Complex`].
53 ///
54 /// # Examples
55 ///
56 /// ```
57 /// use ccmath::Complex;
58 ///
59 /// let z = Complex::new(-1.4, 21.6);
60 /// assert_eq!(z.real(), -1.4);
61 /// ```
62 pub fn imag(self) -> T {
63 self.imag
64 }
65
66 /// Returns the conjugate of this [`Complex`].
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use ccmath::Complex;
72 ///
73 /// let z = Complex::new(4.0, 5.0);
74 /// let z_conjugate = z.conj();
75 ///
76 /// assert_eq!(z_conjugate, Complex::new(4.0, -5.0));
77 /// ```
78 pub fn conj(self) -> Self {
79 Self::new(self.real, -self.imag)
80 }
81
82 /// Returns the square of the absolute value of this [`Complex`].
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// use ccmath::Complex;
88 ///
89 /// let z1 = Complex::new(3.0, 4.0);
90 /// let z2 = Complex::new(4.2, 2.1);
91 ///
92 /// assert_eq!(Complex::square_abs(z1), 25.0);
93 /// assert_eq!(Complex::square_abs(z2), 22.05);
94 /// ```
95 pub fn square_abs(self) -> T {
96 self.real.powi(2) + self.imag.powi(2)
97 }
98
99 /// Returns the absolute value of this [`Complex`].
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use ccmath::Complex;
105 ///
106 /// let z1 = Complex::new(3.0, 4.0);
107 /// let z2 = Complex::new(4.2, 2.1);
108 ///
109 /// assert_eq!(Complex::abs(z1), 5.0);
110 /// assert_eq!(Complex::abs(z2), f32::sqrt(22.05));
111 /// ```
112 pub fn abs(self) -> T {
113 T::sqrt(Self::square_abs(self))
114 }
115
116 /// Returns the argument on the interval (-PI, PI] of this [`Complex`].
117 pub fn arg(self) -> T {
118 if Self::abs(self) == T::zero() {
119 T::zero()
120 } else {
121 self.imag.signum() * T::acos(self.real / Self::abs(self))
122 }
123 }
124
125 /// Returns the square root of this [`Complex`].
126 pub fn sqrt(self) -> Self {
127 Self::new(
128 T::sqrt((self.real + Self::abs(self)) / T::two()),
129 self.imag.signum() * T::sqrt((-self.real + Self::abs(self)) / T::two()),
130 )
131 }
132
133 /// Returns the multiplicative inverse of this [`Complex`].
134 pub fn inv(self) -> Self {
135 Self::conj(self) / Self::square_abs(self)
136 }
137
138 /// Returns this [`Complex`] raised to a power using exponentiation by squaring.
139 pub fn powi(self, exponent: i64) -> Self {
140 match exponent {
141 0 => Self::new(T::one(), T::zero()),
142 1 => self,
143 -1 => Self::inv(self),
144 _ => {
145 if exponent < 0 {
146 Self::inv(Self::powi(self, -exponent))
147 } else if exponent.rem_euclid(2) == 0 {
148 Self::powi(self * self, exponent / 2)
149 } else {
150 self * Self::powi(self * self, (exponent - 1) / 2)
151 }
152 }
153 }
154 }
155
156 /// Returns this [`Complex`] raised to a power using De Moivre's formula.
157 pub fn powf(self, exponent: T) -> Self {
158 let arg_exponent = self.arg() * exponent;
159 Self::new(T::cos(arg_exponent), T::sin(arg_exponent)) * T::powf(Self::abs(self), exponent)
160 }
161
162 /// Returns this [`Complex`] raised to a complex power.
163 pub fn powc(self, exponent: Self) -> Self {
164 Self::powf(self, exponent.real) * Self::exp(Self::ln(self) * Self::i() * exponent.imag)
165 }
166
167 /// Returns e raised to the power of this [`Complex`].
168 pub fn exp(self) -> Self {
169 Self::new(T::cos(self.imag), T::sin(self.imag)) * T::exp(self.real)
170 }
171
172 /// Returns base raised to the power of this [`Complex`].
173 pub fn expf(self, base: T) -> Self {
174 Self::exp(self * T::ln(base))
175 }
176
177 /// Returns the natural logarithm of the absolute value of this [`Complex`].
178 pub fn ln_abs(self) -> T {
179 T::ln(Self::square_abs(self)) / T::two()
180 }
181
182 /// Returns the natural logarithm of this [`Complex`].
183 pub fn ln(self) -> Self {
184 Self::new(Self::ln_abs(self), Self::arg(self))
185 }
186
187 /// Returns the logarithm base 10 of this [`Complex`].
188 pub fn log(self) -> Self {
189 Self::ln(self) / T::ln(T::two() * (T::two() * T::two() + T::one()))
190 // This is equal to 10
191 }
192
193 /// Returns the logarithm base n of this [`Complex`].
194 pub fn logn(self, base: T) -> Self {
195 Self::ln(self) / T::ln(base)
196 }
197}
198
199// Trig
200impl<T: Float> Complex<T> {
201 /// Returns the sine of this [`Complex`].
202 pub fn sin(self) -> Self {
203 Self::new(
204 T::sin(self.real) * T::cosh(self.imag),
205 T::cos(self.real) * T::sinh(self.imag),
206 )
207 }
208
209 /// Returns the cosine of this [`Complex`].
210 pub fn cos(self) -> Self {
211 Self::new(
212 T::cos(self.real) * T::cosh(self.imag),
213 -T::sin(self.real) * T::sinh(self.imag),
214 )
215 }
216
217 /// Returns the tangent of this [`Complex`].
218 pub fn tan(self) -> Self {
219 Self::sin(self) / Self::cos(self)
220 }
221
222 /// Returns the cotangent of this [`Complex`].
223 pub fn cot(self) -> Self {
224 Self::inv(Self::tan(self))
225 }
226
227 /// Returns the secant of this [`Complex`].
228 pub fn sec(self) -> Self {
229 Self::inv(Self::cos(self))
230 }
231
232 /// Returns the cosecant of this [`Complex`].
233 pub fn csc(self) -> Self {
234 Self::inv(Self::sin(self))
235 }
236
237 // Inverse trig
238
239 /// Returns the arcsine of this [`Complex`].
240 pub fn arcsin(self) -> Self {
241 -Self::i() * Self::ln(Self::sqrt(-self.powi(2) + T::one()) + Self::i() * self)
242 }
243
244 /// Returns the arccosine of this [`Complex`].
245 pub fn arccos(self) -> Self {
246 Self::i() * Self::ln(Self::sqrt(-self.powi(2) + T::one()) / Self::i() + self)
247 }
248
249 /// Returns the arctangent of this [`Complex`].
250 pub fn arctan(self) -> Self {
251 Self::arcsin(self / Self::sqrt(self.powi(2) + T::one()))
252 }
253
254 /// Returns the arccotangent of this [`Complex`].
255 pub fn arccot(self) -> Self {
256 Self::arctan(Self::inv(self))
257 }
258
259 /// Returns the arcsecant of this [`Complex`].
260 pub fn arcsec(self) -> Self {
261 Self::arccos(Self::inv(self))
262 }
263
264 // Returns the arccosecant of this [`Complex`].
265 pub fn arccsc(self) -> Self {
266 Self::arcsin(Self::inv(self))
267 }
268
269 // Hyperbolic trig
270
271 /// Returns the hyperbolic sine of this [`Complex`].
272 pub fn sinh(self) -> Self {
273 Self::new(
274 T::sinh(self.real) * T::cos(self.imag),
275 T::cosh(self.real) * T::sin(self.imag),
276 )
277 }
278
279 /// Returns the hyperbolic cosine of this [`Complex`].
280 pub fn cosh(self) -> Self {
281 Self::new(
282 T::cosh(self.real) * T::cos(self.imag),
283 T::sinh(self.real) * T::sin(self.imag),
284 )
285 }
286
287 /// Returns the hyperbolic tangent of this [`Complex`].
288 pub fn tanh(self) -> Self {
289 Self::sinh(self) / Self::cosh(self)
290 }
291
292 /// Returns the hyperbolic cotangent of this [`Complex`].
293 pub fn coth(self) -> Self {
294 Self::inv(Self::tanh(self))
295 }
296
297 /// Returns the hyperbolic secant of this [`Complex`].
298 pub fn sech(self) -> Self {
299 Self::inv(Self::cosh(self))
300 }
301
302 /// Returns the hyperbolic cosecant of this [`Complex`].
303 pub fn csch(self) -> Self {
304 Self::inv(Self::sinh(self))
305 }
306
307 // Inverse hyperbolic trig
308
309 /// Returns the hyperbolic arcsine of this [`Complex`].
310 pub fn arcsinh(self) -> Self {
311 Self::ln(Self::sqrt(self.powi(2) + T::one()) + self)
312 }
313
314 /// Returns the hyperbolic arccosine of this [`Complex`].
315 pub fn arccosh(self) -> Self {
316 Self::ln(Self::sqrt(self.powi(2) - T::one()) + self)
317 }
318
319 /// Returns the hyperbolic arctangent of this [`Complex`].
320 pub fn arctanh(self) -> Self {
321 Self::ln((self + T::one()) / (-self + T::one())) * T::powi(T::two(), -1)
322 }
323
324 /// Returns the hyperbolic arccotangent of this [`Complex`].
325 pub fn arccoth(self) -> Self {
326 Self::arctanh(Self::inv(self))
327 }
328
329 /// Returns the hyperbolic arcsecant of this [`Complex`].
330 pub fn arcsech(self) -> Self {
331 Self::arccosh(Self::inv(self))
332 }
333
334 /// Returns the hyperbolic arccosecant of this [`Complex`].
335 pub fn arccsch(self) -> Self {
336 Self::arcsinh(Self::inv(self))
337 }
338}
339
340// Implements display
341impl<T: Float + Display> Display for Complex<T> {
342 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
343 if self.imag >= T::zero() {
344 write!(f, "{} + {}i", self.real, self.imag)
345 } else {
346 write!(f, "{} - {}i", self.real, self.imag)
347 }
348 }
349}
350
351mod overloading;
352
353#[cfg(test)]
354mod tests;