ccmath/
lib.rs

1/// CCMath: a crate for doing math with complex numbers
2use num_traits::Float;
3use std::fmt::{self, Debug, Display};
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    fn ten() -> Self;
19    fn half() -> Self;
20}
21
22impl<T: Float> Numbers for T {
23    fn two() -> T {
24        T::one() + T::one()
25    }
26    fn ten() -> T {
27        T::two() * (T::two() * T::two() + T::one())
28    }
29    fn half() -> T {
30        T::one() / T::two()
31    }
32}
33
34impl<T: Float> Complex<T> {
35    /// Creates a new [`Complex`].
36    pub fn new(real: T, imag: T) -> Self {
37        Self { real, imag }
38    }
39
40    /// Returns the imaginary number i
41    pub fn i() -> Self {
42        Self::new(T::zero(), T::one())
43    }
44
45    // Returns two i
46    fn two_i() -> Self {
47        Self::new(T::zero(), T::two())
48    }
49
50    /// Returns the real part of this [`Complex`].
51    pub fn real(self) -> T {
52        self.real
53    }
54
55    /// Returns the imaginary part of this [`Complex`].
56    pub fn imag(self) -> T {
57        self.imag
58    }
59
60    /// Returns the conjugate of this [`Complex`].
61    pub fn conj(self) -> Self {
62        Self::new(self.real, -self.imag)
63    }
64
65    /// Returns the square of the absolute value of this [`Complex`].
66    pub fn square_abs(self) -> T {
67        self.real.powi(2) + self.imag.powi(2)
68    }
69
70    /// Returns the absolute value of this [`Complex`].
71    pub fn abs(self) -> T {
72        Self::square_abs(self).sqrt()
73    }
74
75    /// Returns the arg on the interval (-PI, PI] of this [`Complex`].
76    pub fn arg(self) -> T {
77        if self == Self::new(T::zero(), T::zero()) {
78            T::zero()
79        } else {
80            self.imag.signum() * T::acos(self.real / Self::abs(self))
81        }
82    }
83
84    /// Returns the square root of this [`Complex`].
85    pub fn sqrt(self) -> Self {
86        Self::new(
87            ((self.real + self.abs()) / T::two()).sqrt(),
88            self.imag.signum() * ((-self.real + self.abs()) / T::two()).sqrt(),
89        )
90    }
91
92    /// Returns the multiplicative inverse of this [`Complex`].
93    pub fn inv(self) -> Self {
94        Self::conj(self) / Self::square_abs(self)
95    }
96
97    /// Returns this [`Complex`] raised to a power using repeated multiplication.
98    pub fn powi(self, exponent: i64) -> Self {
99        match exponent {
100            0 => Self::new(T::one(), T::zero()),
101            1 => self,
102            -1 => self.inv(),
103            _ => {
104                let mut result = self;
105                for _ in 2..=exponent.abs() {
106                    result *= self;
107                }
108                if exponent < 0 { result.inv() } else { result }
109            }
110        }
111    }
112    // Todo: Implement exponentiating by squaring
113
114    /// Returns this [`Complex`] raised to a power using De Moivre's formula.
115    pub fn powf(self, exponent: T) -> Self {
116        let arg_exponent = self.arg() * exponent;
117        Self::new(T::cos(arg_exponent), T::sin(arg_exponent)) * T::powf(Self::abs(self), exponent)
118    }
119
120    /// Returns this [`Complex`] raised to a complex power.
121    pub fn powc(self, exponent: Self) -> Self {
122        Self::powf(self, exponent.real) * Self::exp(self.ln() * Self::new(T::zero(), exponent.imag))
123    }
124
125    /// Returns e raised to the power of this [`Complex`].
126    pub fn exp(self) -> Self {
127        Self::new(T::cos(self.imag), T::sin(self.imag)) * T::exp(self.real)
128    }
129
130    /// Returns base raised to the power of this [`Complex`].
131    pub fn expf(self, base: T) -> Self {
132        if base == T::zero() {
133            Self::new(T::zero(), T::zero())
134        } else {
135            Self::exp(self * T::ln(base))
136        }
137    }
138
139    /// Returns the natural logarithm of the absolute value of this [`Complex`].
140    pub fn ln_abs(self) -> T {
141        T::ln(Self::square_abs(self)) / T::two()
142    }
143
144    /// Returns the natural logarithm of this [`Complex`].
145    pub fn ln(self) -> Self {
146        Self::new(Self::ln_abs(self), Self::arg(self))
147    }
148
149    /// Returns the logarithm base 10 of this [`Complex`].
150    pub fn log(self) -> Self {
151        Self::ln(self) / T::ln(T::ten())
152    }
153
154    /// Returns the logarithm base n of this [`Complex`].
155    pub fn logn(self, base: T) -> Self {
156        Self::ln(self) / T::ln(base)
157    }
158}
159
160// Trig
161impl<T: Float + Debug> Complex<T> {
162    /// Returns the sine of this [`Complex`].
163    pub fn sin(self) -> Self {
164        Self::new(
165            T::sin(self.real) * T::cosh(self.imag),
166            T::cos(self.real) * T::sinh(self.imag),
167        )
168    }
169
170    /// Returns the cosine of this [`Complex`].
171    pub fn cos(self) -> Self {
172        Self::new(
173            T::cos(self.real) * T::cosh(self.imag),
174            -T::sin(self.real) * T::sinh(self.imag),
175        )
176    }
177
178    /// Returns the tangent of this [`Complex`].
179    pub fn tan(self) -> Self {
180        Self::sin(self) / Self::cos(self)
181    }
182
183    /// Returns the cotangent of this [`Complex`].
184    pub fn cot(self) -> Self {
185        Self::cos(self) / Self::sin(self)
186    }
187
188    /// Returns the secant of this [`Complex`].
189    pub fn sec(self) -> Self {
190        Self::cos(self).inv()
191    }
192
193    /// Returns the cosecant of this [`Complex`].
194    pub fn csc(self) -> Self {
195        Self::sin(self).inv()
196    }
197
198    // Inverse trig
199
200    /// Returns the arcsine of this [`Complex`].
201    pub fn arcsin(self) -> Self {
202        -Self::i() * Self::ln(Self::sqrt(-self.powi(2) + T::one()) + Self::i() * self)
203    }
204
205    /// Returns the arccosine of this [`Complex`].
206    pub fn arccos(self) -> Self {
207        Self::i() * Self::ln(Self::sqrt(-self.powi(2) + T::one()) / Self::i() + self)
208    }
209
210    /// Returns the arctangent of this [`Complex`].
211    pub fn arctan(self) -> Self {
212        Self::two_i().inv()
213            * Self::ln((Self::i() * self + T::one()) / (-Self::i() * self + T::one()))
214    }
215
216    /// Returns the arccotangent of this [`Complex`].
217    pub fn arccot(self) -> Self {
218        Self::arctan(Self::inv(self))
219    }
220
221    /// Returns the arcsecant of this [`Complex`].
222    pub fn arcsec(self) -> Self {
223        Self::arccos(Self::inv(self))
224    }
225
226    // Returns the arccosecant of this [`Complex`].
227    pub fn arccsc(self) -> Self {
228        Self::arcsin(Self::inv(self))
229    }
230
231    // Hyperbolic trig
232
233    /// Returns the hyperbolic sine of this [`Complex`].
234    pub fn sinh(self) -> Self {
235        Self::new(
236            T::sinh(self.real) * T::cos(self.imag),
237            T::cosh(self.real) * T::sin(self.imag),
238        )
239    }
240
241    /// Returns the hyperbolic cosine of this [`Complex`].
242    pub fn cosh(self) -> Self {
243        Self::new(
244            T::cosh(self.real) * T::cos(self.imag),
245            T::sinh(self.real) * T::sin(self.imag),
246        )
247    }
248
249    /// Returns the hyperbolic tangent of this [`Complex`].
250    pub fn tanh(self) -> Self {
251        Self::sinh(self) / Self::cosh(self)
252    }
253
254    /// Returns the hyperbolic cotangent of this [`Complex`].
255    pub fn coth(self) -> Self {
256        Self::cosh(self) / Self::sinh(self)
257    }
258
259    /// Returns the hyperbolic secant of this [`Complex`].
260    pub fn sech(self) -> Self {
261        Self::cosh(self).inv()
262    }
263
264    /// Returns the hyperbolic cosecant of this [`Complex`].
265    pub fn csch(self) -> Self {
266        Self::sinh(self).inv()
267    }
268
269    // Inverse hyperbolic trig
270
271    /// Returns the hyperbolic arcsine of this [`Complex`].
272    pub fn arcsinh(self) -> Self {
273        Self::ln(Self::sqrt(self.powi(2) + T::one()) + self)
274    }
275
276    /// Returns the hyperbolic arccosine of this [`Complex`].
277    pub fn arccosh(self) -> Self {
278        Self::ln(Self::sqrt(self.powi(2) - T::one()) + self)
279    }
280
281    /// Returns the hyperbolic arctangent of this [`Complex`].
282    pub fn arctanh(self) -> Self {
283        Self::ln((self + T::one()) / (-self + T::one())) * T::half()
284    }
285
286    /// Returns the hyperbolic arccotangent of this [`Complex`].
287    pub fn arccoth(self) -> Self {
288        Self::arctanh(Self::inv(self))
289    }
290
291    /// Returns the hyperbolic arcsecant of this [`Complex`].
292    pub fn arcsech(self) -> Self {
293        Self::arccosh(Self::inv(self))
294    }
295
296    /// Returns the hyperbolic arccosecant of this [`Complex`].
297    pub fn arccsch(self) -> Self {
298        Self::arcsinh(Self::inv(self))
299    }
300}
301
302// Implements display
303impl<T: Float + Display> fmt::Display for Complex<T> {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        // The `f` value implements the `Write` trait, which is what the
306        // write! macro is expecting. Note that this formatting ignores the
307        // various flags provided to format strings.
308        if self.imag >= T::zero() {
309            write!(f, "{} + {}i", self.real, self.imag)
310        } else {
311            write!(f, "{} - {}i", self.real, self.imag)
312        }
313    }
314}
315
316mod overloading;
317
318#[cfg(test)]
319mod tests;