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;