use scirs2_core::numeric::{One, Zero};
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Sub};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Complex32 {
pub real: f32,
pub imag: f32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Complex64 {
pub real: f64,
pub imag: f64,
}
impl Complex32 {
pub fn new(real: f32, imag: f32) -> Self {
Self { real, imag }
}
pub fn from_real(real: f32) -> Self {
Self { real, imag: 0.0 }
}
pub fn from_imag(imag: f32) -> Self {
Self { real: 0.0, imag }
}
pub fn magnitude(&self) -> f32 {
(self.real * self.real + self.imag * self.imag).sqrt()
}
pub fn phase(&self) -> f32 {
self.imag.atan2(self.real)
}
pub fn conjugate(&self) -> Self {
Self {
real: self.real,
imag: -self.imag,
}
}
pub fn to_polar(&self) -> (f32, f32) {
(self.magnitude(), self.phase())
}
pub fn from_polar(magnitude: f32, phase: f32) -> Self {
Self {
real: magnitude * phase.cos(),
imag: magnitude * phase.sin(),
}
}
}
impl Complex64 {
pub fn new(real: f64, imag: f64) -> Self {
Self { real, imag }
}
pub fn from_real(real: f64) -> Self {
Self { real, imag: 0.0 }
}
pub fn from_imag(imag: f64) -> Self {
Self { real: 0.0, imag }
}
pub fn magnitude(&self) -> f64 {
(self.real * self.real + self.imag * self.imag).sqrt()
}
pub fn phase(&self) -> f64 {
self.imag.atan2(self.real)
}
pub fn conjugate(&self) -> Self {
Self {
real: self.real,
imag: -self.imag,
}
}
pub fn to_polar(&self) -> (f64, f64) {
(self.magnitude(), self.phase())
}
pub fn from_polar(magnitude: f64, phase: f64) -> Self {
Self {
real: magnitude * phase.cos(),
imag: magnitude * phase.sin(),
}
}
}
impl Add for Complex32 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
real: self.real + other.real,
imag: self.imag + other.imag,
}
}
}
impl Sub for Complex32 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
real: self.real - other.real,
imag: self.imag - other.imag,
}
}
}
impl Mul for Complex32 {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self {
real: self.real * other.real - self.imag * other.imag,
imag: self.real * other.imag + self.imag * other.real,
}
}
}
impl Div for Complex32 {
type Output = Self;
fn div(self, other: Self) -> Self {
let denom = other.real * other.real + other.imag * other.imag;
Self {
real: (self.real * other.real + self.imag * other.imag) / denom,
imag: (self.imag * other.real - self.real * other.imag) / denom,
}
}
}
impl Neg for Complex32 {
type Output = Self;
fn neg(self) -> Self {
Self {
real: -self.real,
imag: -self.imag,
}
}
}
impl Add for Complex64 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
real: self.real + other.real,
imag: self.imag + other.imag,
}
}
}
impl Sub for Complex64 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
real: self.real - other.real,
imag: self.imag - other.imag,
}
}
}
impl Mul for Complex64 {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self {
real: self.real * other.real - self.imag * other.imag,
imag: self.real * other.imag + self.imag * other.real,
}
}
}
impl Div for Complex64 {
type Output = Self;
fn div(self, other: Self) -> Self {
let denom = other.real * other.real + other.imag * other.imag;
Self {
real: (self.real * other.real + self.imag * other.imag) / denom,
imag: (self.imag * other.real - self.real * other.imag) / denom,
}
}
}
impl Neg for Complex64 {
type Output = Self;
fn neg(self) -> Self {
Self {
real: -self.real,
imag: -self.imag,
}
}
}
impl Zero for Complex32 {
fn zero() -> Self {
Self {
real: 0.0,
imag: 0.0,
}
}
fn is_zero(&self) -> bool {
self.real == 0.0 && self.imag == 0.0
}
}
impl One for Complex32 {
fn one() -> Self {
Self {
real: 1.0,
imag: 0.0,
}
}
}
impl Zero for Complex64 {
fn zero() -> Self {
Self {
real: 0.0,
imag: 0.0,
}
}
fn is_zero(&self) -> bool {
self.real == 0.0 && self.imag == 0.0
}
}
impl One for Complex64 {
fn one() -> Self {
Self {
real: 1.0,
imag: 0.0,
}
}
}
impl Default for Complex32 {
fn default() -> Self {
Self::zero()
}
}
impl Default for Complex64 {
fn default() -> Self {
Self::zero()
}
}
impl fmt::Display for Complex32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.imag >= 0.0 {
write!(f, "{}+{}i", self.real, self.imag)
} else {
write!(f, "{}{}i", self.real, self.imag)
}
}
}
impl fmt::Display for Complex64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.imag >= 0.0 {
write!(f, "{}+{}i", self.real, self.imag)
} else {
write!(f, "{}{}i", self.real, self.imag)
}
}
}
impl From<f32> for Complex32 {
fn from(real: f32) -> Self {
Self::from_real(real)
}
}
impl From<f64> for Complex64 {
fn from(real: f64) -> Self {
Self::from_real(real)
}
}
impl From<Complex32> for Complex64 {
fn from(c: Complex32) -> Self {
Self {
real: c.real as f64,
imag: c.imag as f64,
}
}
}
impl From<Complex64> for Complex32 {
fn from(c: Complex64) -> Self {
Self {
real: c.real as f32,
imag: c.imag as f32,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_complex32_arithmetic() {
let a = Complex32::new(3.0, 4.0);
let b = Complex32::new(1.0, 2.0);
let sum = a + b;
assert_eq!(sum.real, 4.0);
assert_eq!(sum.imag, 6.0);
let product = a * b;
assert_eq!(product.real, -5.0);
assert_eq!(product.imag, 10.0);
}
#[test]
fn test_complex64_magnitude() {
let c = Complex64::new(3.0, 4.0);
assert_eq!(c.magnitude(), 5.0);
}
#[test]
fn test_complex_conjugate() {
let c = Complex32::new(3.0, 4.0);
let conj = c.conjugate();
assert_eq!(conj.real, 3.0);
assert_eq!(conj.imag, -4.0);
}
}