num_complex/
complex_float.rs

1// Keeps us from accidentally creating a recursive impl rather than a real one.
2#![deny(unconditional_recursion)]
3
4use core::ops::Neg;
5
6use num_traits::{Float, FloatConst, Num, NumCast};
7
8use crate::Complex;
9
10mod private {
11    use num_traits::{Float, FloatConst};
12
13    use crate::Complex;
14
15    pub trait Seal {}
16
17    impl<T> Seal for T where T: Float + FloatConst {}
18    impl<T: Float + FloatConst> Seal for Complex<T> {}
19}
20
21/// Generic trait for floating point complex numbers.
22///
23/// This trait defines methods which are common to complex floating point
24/// numbers and regular floating point numbers.
25///
26/// This trait is sealed to prevent it from being implemented by anything other
27/// than floating point scalars and [Complex] floats.
28pub trait ComplexFloat: Num + NumCast + Copy + Neg<Output = Self> + private::Seal {
29    /// The type used to represent the real coefficients of this complex number.
30    type Real: Float + FloatConst;
31
32    /// Returns `true` if this value is `NaN` and false otherwise.
33    fn is_nan(self) -> bool;
34
35    /// Returns `true` if this value is positive infinity or negative infinity and
36    /// false otherwise.
37    fn is_infinite(self) -> bool;
38
39    /// Returns `true` if this number is neither infinite nor `NaN`.
40    fn is_finite(self) -> bool;
41
42    /// Returns `true` if the number is neither zero, infinite,
43    /// [subnormal](http://en.wikipedia.org/wiki/Denormal_number), or `NaN`.
44    fn is_normal(self) -> bool;
45
46    /// Take the reciprocal (inverse) of a number, `1/x`. See also [Complex::finv].
47    fn recip(self) -> Self;
48
49    /// Raises `self` to a signed integer power.
50    fn powi(self, exp: i32) -> Self;
51
52    /// Raises `self` to a real power.
53    fn powf(self, exp: Self::Real) -> Self;
54
55    /// Raises `self` to a complex power.
56    fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real>;
57
58    /// Take the square root of a number.
59    fn sqrt(self) -> Self;
60
61    /// Returns `e^(self)`, (the exponential function).
62    fn exp(self) -> Self;
63
64    /// Returns `2^(self)`.
65    fn exp2(self) -> Self;
66
67    /// Returns `base^(self)`.
68    fn expf(self, base: Self::Real) -> Self;
69
70    /// Returns the natural logarithm of the number.
71    fn ln(self) -> Self;
72
73    /// Returns the logarithm of the number with respect to an arbitrary base.
74    fn log(self, base: Self::Real) -> Self;
75
76    /// Returns the base 2 logarithm of the number.
77    fn log2(self) -> Self;
78
79    /// Returns the base 10 logarithm of the number.
80    fn log10(self) -> Self;
81
82    /// Take the cubic root of a number.
83    fn cbrt(self) -> Self;
84
85    /// Computes the sine of a number (in radians).
86    fn sin(self) -> Self;
87
88    /// Computes the cosine of a number (in radians).
89    fn cos(self) -> Self;
90
91    /// Computes the tangent of a number (in radians).
92    fn tan(self) -> Self;
93
94    /// Computes the arcsine of a number. Return value is in radians in
95    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
96    /// [-1, 1].
97    fn asin(self) -> Self;
98
99    /// Computes the arccosine of a number. Return value is in radians in
100    /// the range [0, pi] or NaN if the number is outside the range
101    /// [-1, 1].
102    fn acos(self) -> Self;
103
104    /// Computes the arctangent of a number. Return value is in radians in the
105    /// range [-pi/2, pi/2];
106    fn atan(self) -> Self;
107
108    /// Hyperbolic sine function.
109    fn sinh(self) -> Self;
110
111    /// Hyperbolic cosine function.
112    fn cosh(self) -> Self;
113
114    /// Hyperbolic tangent function.
115    fn tanh(self) -> Self;
116
117    /// Inverse hyperbolic sine function.
118    fn asinh(self) -> Self;
119
120    /// Inverse hyperbolic cosine function.
121    fn acosh(self) -> Self;
122
123    /// Inverse hyperbolic tangent function.
124    fn atanh(self) -> Self;
125
126    /// Returns the real part of the number.
127    fn re(self) -> Self::Real;
128
129    /// Returns the imaginary part of the number.
130    fn im(self) -> Self::Real;
131
132    /// Returns the absolute value of the number. See also [Complex::norm]
133    fn abs(self) -> Self::Real;
134
135    /// Returns the L1 norm `|re| + |im|` -- the [Manhattan distance] from the origin.
136    ///
137    /// [Manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
138    fn l1_norm(&self) -> Self::Real;
139
140    /// Computes the argument of the number.
141    fn arg(self) -> Self::Real;
142
143    /// Computes the complex conjugate of the number.
144    ///
145    /// Formula: `a+bi -> a-bi`
146    fn conj(self) -> Self;
147}
148
149macro_rules! forward {
150    ($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
151        => {$(
152            #[inline]
153            fn $method(self $( , $arg : $ty )* ) -> $ret {
154                $base::$method(self $( , $arg )* )
155            }
156        )*};
157}
158
159macro_rules! forward_ref {
160    ($( Self :: $method:ident ( & self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
161        => {$(
162            #[inline]
163            fn $method(self $( , $arg : $ty )* ) -> $ret {
164                Self::$method(&self $( , $arg )* )
165            }
166        )*};
167}
168
169impl<T> ComplexFloat for T
170where
171    T: Float + FloatConst,
172{
173    type Real = T;
174
175    fn re(self) -> Self::Real {
176        self
177    }
178
179    fn im(self) -> Self::Real {
180        T::zero()
181    }
182
183    fn l1_norm(&self) -> Self::Real {
184        self.abs()
185    }
186
187    fn arg(self) -> Self::Real {
188        if self.is_nan() {
189            self
190        } else if self.is_sign_negative() {
191            T::PI()
192        } else {
193            T::zero()
194        }
195    }
196
197    fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real> {
198        Complex::new(self, T::zero()).powc(exp)
199    }
200
201    fn conj(self) -> Self {
202        self
203    }
204
205    fn expf(self, base: Self::Real) -> Self {
206        base.powf(self)
207    }
208
209    forward! {
210        Float::is_normal(self) -> bool;
211        Float::is_infinite(self) -> bool;
212        Float::is_finite(self) -> bool;
213        Float::is_nan(self) -> bool;
214        Float::recip(self) -> Self;
215        Float::powi(self, n: i32) -> Self;
216        Float::powf(self, f: Self) -> Self;
217        Float::sqrt(self) -> Self;
218        Float::cbrt(self) -> Self;
219        Float::exp(self) -> Self;
220        Float::exp2(self) -> Self;
221        Float::ln(self) -> Self;
222        Float::log(self, base: Self) -> Self;
223        Float::log2(self) -> Self;
224        Float::log10(self) -> Self;
225        Float::sin(self) -> Self;
226        Float::cos(self) -> Self;
227        Float::tan(self) -> Self;
228        Float::asin(self) -> Self;
229        Float::acos(self) -> Self;
230        Float::atan(self) -> Self;
231        Float::sinh(self) -> Self;
232        Float::cosh(self) -> Self;
233        Float::tanh(self) -> Self;
234        Float::asinh(self) -> Self;
235        Float::acosh(self) -> Self;
236        Float::atanh(self) -> Self;
237        Float::abs(self) -> Self;
238    }
239}
240
241impl<T: Float + FloatConst> ComplexFloat for Complex<T> {
242    type Real = T;
243
244    fn re(self) -> Self::Real {
245        self.re
246    }
247
248    fn im(self) -> Self::Real {
249        self.im
250    }
251
252    fn abs(self) -> Self::Real {
253        self.norm()
254    }
255
256    fn recip(self) -> Self {
257        self.finv()
258    }
259
260    // `Complex::l1_norm` uses `Signed::abs` to let it work
261    // for integers too, but we can just use `Float::abs`.
262    fn l1_norm(&self) -> Self::Real {
263        self.re.abs() + self.im.abs()
264    }
265
266    // `Complex::is_*` methods use `T: FloatCore`, but we
267    // have `T: Float` that can do them as well.
268    fn is_nan(self) -> bool {
269        self.re.is_nan() || self.im.is_nan()
270    }
271
272    fn is_infinite(self) -> bool {
273        !self.is_nan() && (self.re.is_infinite() || self.im.is_infinite())
274    }
275
276    fn is_finite(self) -> bool {
277        self.re.is_finite() && self.im.is_finite()
278    }
279
280    fn is_normal(self) -> bool {
281        self.re.is_normal() && self.im.is_normal()
282    }
283
284    forward! {
285        Complex::arg(self) -> Self::Real;
286        Complex::powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real>;
287        Complex::exp2(self) -> Self;
288        Complex::log(self, base: Self::Real) -> Self;
289        Complex::log2(self) -> Self;
290        Complex::log10(self) -> Self;
291        Complex::powf(self, f: Self::Real) -> Self;
292        Complex::sqrt(self) -> Self;
293        Complex::cbrt(self) -> Self;
294        Complex::exp(self) -> Self;
295        Complex::expf(self, base: Self::Real) -> Self;
296        Complex::ln(self) -> Self;
297        Complex::sin(self) -> Self;
298        Complex::cos(self) -> Self;
299        Complex::tan(self) -> Self;
300        Complex::asin(self) -> Self;
301        Complex::acos(self) -> Self;
302        Complex::atan(self) -> Self;
303        Complex::sinh(self) -> Self;
304        Complex::cosh(self) -> Self;
305        Complex::tanh(self) -> Self;
306        Complex::asinh(self) -> Self;
307        Complex::acosh(self) -> Self;
308        Complex::atanh(self) -> Self;
309    }
310
311    forward_ref! {
312        Self::powi(&self, n: i32) -> Self;
313        Self::conj(&self) -> Self;
314    }
315}
316
317#[cfg(test)]
318mod test {
319    use crate::{
320        complex_float::ComplexFloat,
321        test::{_0_0i, _0_1i, _1_0i, _1_1i, float::close},
322        Complex,
323    };
324    use std::f64; // for constants before Rust 1.43.
325
326    fn closef(a: f64, b: f64) -> bool {
327        close_to_tolf(a, b, 1e-10)
328    }
329
330    fn close_to_tolf(a: f64, b: f64, tol: f64) -> bool {
331        // returns true if a and b are reasonably close
332        let close = (a == b) || (a - b).abs() < tol;
333        if !close {
334            println!("{:?} != {:?}", a, b);
335        }
336        close
337    }
338
339    #[test]
340    fn test_exp2() {
341        assert!(close(ComplexFloat::exp2(_0_0i), _1_0i));
342        assert!(closef(<f64 as ComplexFloat>::exp2(0.), 1.));
343    }
344
345    #[test]
346    fn test_exp() {
347        assert!(close(ComplexFloat::exp(_0_0i), _1_0i));
348        assert!(closef(ComplexFloat::exp(0.), 1.));
349    }
350
351    #[test]
352    fn test_powi() {
353        assert!(close(ComplexFloat::powi(_0_1i, 4), _1_0i));
354        assert!(closef(ComplexFloat::powi(-1., 4), 1.));
355    }
356
357    #[test]
358    fn test_powz() {
359        assert!(close(ComplexFloat::powc(_1_0i, _0_1i), _1_0i));
360        assert!(close(ComplexFloat::powc(1., _0_1i), _1_0i));
361    }
362
363    #[test]
364    fn test_log2() {
365        assert!(close(ComplexFloat::log2(_1_0i), _0_0i));
366        assert!(closef(ComplexFloat::log2(1.), 0.));
367    }
368
369    #[test]
370    fn test_log10() {
371        assert!(close(ComplexFloat::log10(_1_0i), _0_0i));
372        assert!(closef(ComplexFloat::log10(1.), 0.));
373    }
374
375    #[test]
376    fn test_conj() {
377        assert_eq!(ComplexFloat::conj(_0_1i), Complex::new(0., -1.));
378        assert_eq!(ComplexFloat::conj(1.), 1.);
379    }
380
381    #[test]
382    fn test_is_nan() {
383        assert!(!ComplexFloat::is_nan(_1_0i));
384        assert!(!ComplexFloat::is_nan(1.));
385
386        assert!(ComplexFloat::is_nan(Complex::new(f64::NAN, f64::NAN)));
387        assert!(ComplexFloat::is_nan(f64::NAN));
388    }
389
390    #[test]
391    fn test_is_infinite() {
392        assert!(!ComplexFloat::is_infinite(_1_0i));
393        assert!(!ComplexFloat::is_infinite(1.));
394
395        assert!(ComplexFloat::is_infinite(Complex::new(
396            f64::INFINITY,
397            f64::INFINITY
398        )));
399        assert!(ComplexFloat::is_infinite(f64::INFINITY));
400    }
401
402    #[test]
403    fn test_is_finite() {
404        assert!(ComplexFloat::is_finite(_1_0i));
405        assert!(ComplexFloat::is_finite(1.));
406
407        assert!(!ComplexFloat::is_finite(Complex::new(
408            f64::INFINITY,
409            f64::INFINITY
410        )));
411        assert!(!ComplexFloat::is_finite(f64::INFINITY));
412    }
413
414    #[test]
415    fn test_is_normal() {
416        assert!(ComplexFloat::is_normal(_1_1i));
417        assert!(ComplexFloat::is_normal(1.));
418
419        assert!(!ComplexFloat::is_normal(Complex::new(
420            f64::INFINITY,
421            f64::INFINITY
422        )));
423        assert!(!ComplexFloat::is_normal(f64::INFINITY));
424    }
425
426    #[test]
427    fn test_arg() {
428        assert!(closef(
429            ComplexFloat::arg(_0_1i),
430            core::f64::consts::FRAC_PI_2
431        ));
432
433        assert!(closef(ComplexFloat::arg(-1.), core::f64::consts::PI));
434        assert!(closef(ComplexFloat::arg(-0.), core::f64::consts::PI));
435        assert!(closef(ComplexFloat::arg(0.), 0.));
436        assert!(closef(ComplexFloat::arg(1.), 0.));
437        assert!(ComplexFloat::arg(f64::NAN).is_nan());
438    }
439}