symphonia_core/dsp/
complex.rs

1// Symphonia
2// Copyright (c) 2019-2022 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8//! The `complex` module implements a 32-bit floating point complex number.
9
10/// A complex number.
11#[derive(Copy, Clone, Default, Debug, PartialEq)]
12#[repr(C)]
13pub struct Complex {
14    /// The real component.
15    pub re: f32,
16    /// The imaginary component.
17    pub im: f32,
18}
19
20impl Complex {
21    /// Create a new complex number.
22    #[inline(always)]
23    pub fn new(re: f32, im: f32) -> Self {
24        Self { re, im }
25    }
26
27    /// Create a complex number with a value of `0 + j1`.
28    #[inline(always)]
29    pub fn j() -> Self {
30        Self { re: 0.0, im: 1.0 }
31    }
32
33    /// Scale the complex number.
34    #[inline(always)]
35    pub fn scale(&self, scale: f32) -> Self {
36        Self { re: self.re * scale, im: self.im * scale }
37    }
38
39    /// Take the complex conjugate of `self`.
40    ///
41    /// For a complex number defined as `a + jb` the complex conjugate is defined to be `a - jb`.
42    #[inline(always)]
43    pub fn conj(&self) -> Self {
44        Self { re: self.re, im: -self.im }
45    }
46}
47
48impl core::ops::Add for Complex {
49    type Output = Complex;
50
51    #[inline(always)]
52    fn add(self, rhs: Self) -> Self::Output {
53        Self::Output { re: self.re + rhs.re, im: self.im + rhs.im }
54    }
55}
56
57impl core::ops::AddAssign for Complex {
58    #[inline(always)]
59    fn add_assign(&mut self, rhs: Self) {
60        *self = *self + rhs;
61    }
62}
63
64impl core::ops::Sub for Complex {
65    type Output = Complex;
66
67    #[inline(always)]
68    fn sub(self, rhs: Self) -> Self::Output {
69        Self::Output { re: self.re - rhs.re, im: self.im - rhs.im }
70    }
71}
72
73impl core::ops::SubAssign for Complex {
74    #[inline(always)]
75    fn sub_assign(&mut self, rhs: Self) {
76        *self = *self - rhs;
77    }
78}
79
80impl core::ops::Mul for Complex {
81    type Output = Complex;
82
83    #[inline(always)]
84    fn mul(self, rhs: Self) -> Self::Output {
85        Self::Output {
86            re: (self.re * rhs.re) - (self.im * rhs.im),
87            im: (self.re * rhs.im) + (self.im * rhs.re),
88        }
89    }
90}
91
92impl core::ops::MulAssign for Complex {
93    #[inline(always)]
94    fn mul_assign(&mut self, rhs: Self) {
95        *self = *self * rhs;
96    }
97}
98
99impl core::ops::Div for Complex {
100    type Output = Complex;
101
102    #[inline(always)]
103    fn div(self, rhs: Self) -> Self::Output {
104        let denom = rhs.re * rhs.re + rhs.im * rhs.im;
105
106        Self::Output {
107            re: (self.re * rhs.re + self.im * rhs.im) / denom,
108            im: (self.im * rhs.re - self.re * rhs.im) / denom,
109        }
110    }
111}
112
113impl core::ops::DivAssign for Complex {
114    #[inline(always)]
115    fn div_assign(&mut self, rhs: Self) {
116        *self = *self / rhs;
117    }
118}
119
120impl core::ops::Mul<f32> for Complex {
121    type Output = Complex;
122
123    #[inline(always)]
124    fn mul(self, rhs: f32) -> Self::Output {
125        Self::Output { re: self.re * rhs, im: self.im * rhs }
126    }
127}
128
129impl core::ops::Div<f32> for Complex {
130    type Output = Complex;
131
132    #[inline(always)]
133    fn div(self, rhs: f32) -> Self::Output {
134        Self::Output { re: self.re / rhs, im: self.im / rhs }
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn verify_complex() {
144        assert_eq!(Complex::j(), Complex::new(0.0, 1.0));
145
146        // Conjugate
147        assert_eq!(Complex::new(1.0, 10.0).conj(), Complex::new(1.0, -10.0));
148
149        // Scale
150        assert_eq!(Complex::new(5.0, 2.0).scale(3.0), Complex::new(15.0, 6.0));
151
152        // Addition
153        assert_eq!(Complex::new(3.0, 13.0) + Complex::new(7.0, 17.0), Complex::new(10.0, 30.0));
154
155        // Subtraction
156        assert_eq!(Complex::new(3.0, 13.0) - Complex::new(7.0, 17.0), Complex::new(-4.0, -4.0));
157
158        // Multiplication
159        assert_eq!(Complex::new(3.0, 13.0) * Complex::new(7.0, 17.0), Complex::new(-200.0, 142.0));
160
161        // Division
162        assert_eq!(
163            Complex::new(3.0, 13.0) / Complex::new(7.0, 17.0),
164            Complex::new(121.0 / 169.0, 20.0 / 169.0)
165        );
166
167        // Scalar Multiplication
168        assert_eq!(Complex::new(5.0, 2.0) * 3.0, Complex::new(15.0, 6.0));
169
170        // Scalar Division
171        assert_eq!(Complex::new(4.0, 2.0) / 2.0, Complex::new(2.0, 1.0));
172    }
173}