use std::ops;
pub mod consts {
use super::Complex;
#[allow(unused)]
pub const I: Complex = Complex {real: 0.0, imag: 1.0};
}
use consts::I;
#[allow(unused)]
pub fn pow(a: Complex, b: Complex) -> Complex {
let amod2 = a.real*a.real + a.imag*a.imag;
amod2.powf(b.real/2.0) * (-b.imag*a.arg()).exp() * Complex::from_polar(1.0, b.real*a.arg() + 0.5*b.imag*(amod2.ln()))
}
#[allow(unused)]
pub fn exp(z: Complex) -> Complex {
z.real.exp()*Complex::from_polar(1.0, z.imag)
}
#[allow(unused)]
pub fn ln(z: Complex) -> Complex {
z.modulus().ln() + z.arg()*I
}
#[allow(unused)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Complex {
pub real: f32,
pub imag: f32,
}
impl Complex {
pub fn from_polar(r: f32, th: f32) -> Self {
Complex {
real: r * f32::cos(th),
imag: r * f32::sin(th),
}
}
pub fn conj(self) -> Self {
Complex {
real: self.real,
imag: - self.imag,
}
}
pub fn arg(self) -> f32 {
self.imag.atan2(self.real)
}
pub fn modulus(self) -> f32 {
(self.conj() * self).real.sqrt()
}
}
impl ops::Add for Complex {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Complex {
real: self.real + rhs.real,
imag: self.imag + rhs.imag,
}
}
}
impl ops::Sub for Complex {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Complex {
real: self.real - rhs.real,
imag: self.imag - rhs.imag,
}
}
}
impl ops::Mul for Complex {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Complex {
real: (self.real * rhs.real) - (self.imag * rhs.imag),
imag: (self.real * rhs.imag) + (self.imag * rhs.real),
}
}
}
impl ops::Div for Complex {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
if rhs.real == 0_f32 && rhs.imag == 0_f32 {
panic!("Cannot divide by 0!");
}
let s = rhs.real*rhs.real + rhs.imag*rhs.imag;
Complex {
real: (self.real*rhs.real + self.imag*rhs.imag)/s,
imag: (self.imag*rhs.real - self.real*rhs.imag)/s,
}
}
}
impl ops::Add<f32> for Complex {
type Output = Complex;
fn add(self, rhs: f32) -> Self::Output {
Complex {
real: self.real + rhs,
imag: self.imag,
}
}
}
impl ops::Sub<f32> for Complex {
type Output = Complex;
fn sub(self, rhs: f32) -> Self::Output {
Complex {
real: self.real - rhs,
imag: self.imag,
}
}
}
impl ops::Mul<f32> for Complex {
type Output = Complex;
fn mul(self, rhs: f32) -> Self::Output {
Complex {
real: self.real * rhs,
imag: self.imag * rhs,
}
}
}
impl ops::Div<f32> for Complex {
type Output = Complex;
fn div(self, rhs: f32) -> Self::Output {
assert_eq!(rhs, 0_f32, "Cannot divide by 0!");
Complex {
real: self.real / rhs,
imag: self.imag / rhs,
}
}
}
impl ops::Add<Complex> for f32 {
type Output = Complex;
fn add(self, rhs: Complex) -> Self::Output {
rhs + self
}
}
impl ops::Sub<Complex> for f32 {
type Output = Complex;
fn sub(self, rhs: Complex) -> Self::Output {
rhs + self
}
}
impl ops::Mul<Complex> for f32 {
type Output = Complex;
fn mul(self, rhs: Complex) -> Self::Output {
rhs * self
}
}
impl ops::Div<Complex> for f32 {
type Output = Complex;
fn div(self, rhs: Complex) -> Self::Output {
rhs / self
}
}
impl std::fmt::Display for Complex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let sign = if self.imag < 0.0 { "-" } else { "+" };
write!(f, "{}{}{}i", self.real, sign, self.imag*self.imag.signum())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_addition() {
let a = Complex { real: 1.0, imag: 2.0 };
let b = Complex { real: 3.0, imag: 4.0 };
let result = a + b;
assert_eq!(result, Complex { real: 4.0, imag: 6.0 });
}
#[test]
fn test_subtraction() {
let a = Complex { real: 5.0, imag: 6.0 };
let b = Complex { real: 3.0, imag: 4.0 };
let result = a - b;
assert_eq!(result, Complex { real: 2.0, imag: 2.0 });
}
#[test]
fn test_multiplication() {
let a = Complex { real: 1.0, imag: 2.0 };
let b = Complex { real: 3.0, imag: 4.0 };
let result = a * b;
assert_eq!(result, Complex { real: -5.0, imag: 10.0 });
}
#[test]
fn test_division() {
let a = Complex { real: 1.0, imag: 2.0 };
let b = Complex { real: 3.0, imag: 4.0 };
let result = a / b;
assert_eq!(result, Complex { real: 0.44, imag: 0.08 });
}
#[test]
#[should_panic(expected = "Cannot divide by 0!")]
fn test_division_by_zero() {
let a = Complex { real: 1.0, imag: 2.0 };
let b = Complex { real: 0.0, imag: 0.0 };
let _ = a / b;
}
#[test]
fn test_conjugate() {
let a = Complex { real: 1.0, imag: 2.0 };
let result = a.conj();
assert_eq!(result, Complex { real: 1.0, imag: -2.0 });
}
#[test]
fn test_modulus() {
let a = Complex { real: 3.0, imag: 4.0 };
let result = a.modulus();
assert_eq!(result, 5.0);
}
#[test]
fn test_argument() {
let a = Complex { real: 1.0, imag: 1.0 };
let result = a.arg();
assert!((result - std::f32::consts::FRAC_PI_4).abs() < 1e-6);
}
#[test]
fn test_from_polar() {
let r = 2.0;
let theta = std::f32::consts::PI / 4.0;
let result = Complex::from_polar(r, theta);
assert!((result.real - 1.4142).abs() < 1e-4);
assert!((result.imag - 1.4142).abs() < 1e-4);
}
#[test]
fn test_display_format() {
let a = Complex { real: 1.0, imag: -2.0 };
assert_eq!(a.to_string(), "1-2i");
let b = Complex { real: 3.5, imag: 4.0 };
assert_eq!(b.to_string(), "3.5+4i");
}
}