use std::fmt;
use std::fmt::{Debug, Formatter};
use std::ops::{Add, Mul, Sub};
pub const COMPLEX_ZERO: Complex<f64> = Complex::<f64> { re: 0f64, im: 0f64 };
pub trait Sqr {
fn square_root(self) -> Self;
}
impl Sqr for f32 {
fn square_root(self) -> Self {
self.sqrt()
}
}
impl Sqr for f64 {
fn square_root(self) -> Self {
self.sqrt()
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct Complex<T> {
pub re: T,
pub im: T,
}
impl Complex<f64> {
pub fn exp_im(theta: f64) -> Complex<f64> {
Complex {
re: theta.cos(),
im: theta.sin(),
}
}
}
impl Complex<f32> {
pub fn exp_im(theta: f32) -> Complex<f32> {
Complex {
re: theta.cos(),
im: theta.sin(),
}
}
}
impl<T: Add<Output = T>> Add for Complex<T> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Complex {
re: self.re.add(rhs.re),
im: self.im.add(rhs.im),
}
}
}
impl<T: Sub<Output = T>> Sub for Complex<T> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Complex {
re: self.re.sub(rhs.re),
im: self.im.sub(rhs.im),
}
}
}
impl<T: Mul<Output = T> + Add<Output = T> + Sub<Output = T> + Copy> Mul for Complex<T> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Complex {
re: self.re.mul(rhs.re).sub(self.im.mul(rhs.im)),
im: self.re.mul(rhs.im).add(self.im.mul(rhs.re)),
}
}
}
impl Mul<f64> for Complex<f64> {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
Complex {
re: self.re.mul(rhs),
im: self.im.mul(rhs),
}
}
}
impl Mul<Complex<f64>> for f64 {
type Output = Complex<f64>;
fn mul(self, rhs: Complex<f64>) -> Self::Output {
Complex {
re: rhs.re.mul(self),
im: rhs.im.mul(self),
}
}
}
impl<T: Add<Output = T> + Mul<Output = T> + Copy> Complex<T> {
pub fn abs_square(self) -> T {
self.re.mul(self.re).add(self.im.mul(self.im))
}
}
impl<T: Add<Output = T> + Mul<Output = T> + Sqr + Copy> Complex<T> {
pub fn abs(&self) -> T {
self.abs_square().square_root()
}
}
impl<T: fmt::Display> fmt::Display for Complex<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{} + {}i", self.re, self.im)
}
}
#[macro_export]
macro_rules! complex {
($r:expr, $i:expr) => {
Complex::<f64> { re: $r, im: $i }
};
}
#[macro_export]
macro_rules! complex_re_array {
( $( $x:expr ),* ) => {
[
$(
Complex::<f64> {
re: $x,
im: 0f64
}
),*
]
};
}
#[macro_export]
macro_rules! complex_im_array {
( $( $x:expr ),* ) => {
[
$(
Complex::<f64> {
re: 0f64,
im: $x
}
),*
]
};
}
#[macro_export]
macro_rules! complex_re_vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec: Vec<Complex<f64>> = Vec::new();
$(
temp_vec.push(
Complex::<f64> {
re: $x,
im: 0f64
}
);
)*
temp_vec
}
};
}
#[macro_export]
macro_rules! complex_im_vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec: Vec<Complex<f64>> = Vec::new();
$(
temp_vec.push(
Complex::<f64> {
re: 0f64,
im: $x,
}
);
)*
temp_vec
}
};
}
#[macro_export]
macro_rules! complex_re {
($r:expr) => {
Complex::<f64> { re: $r, im: 0f64 }
};
}
#[macro_export]
macro_rules! complex_im {
($i:expr) => {
Complex::<f64> { re: 0f64, im: $i }
};
}
#[rustfmt::skip]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn complex_imaginary_and_imaginary() {
let num_one = Complex::<i8>{ re: 0, im: 9};
let num_two = Complex::<i8>{ re: 0, im: 2};
assert_eq!(num_one.mul(num_two), Complex::<i8>{ re: -18, im: 0})
}
#[test]
fn complex_imaginary_and_real() {
let num_one = Complex::<i8>{ re: 0, im: -9};
let num_two = Complex::<i8>{ re: 2, im: 0};
assert_eq!(num_one.mul(num_two), Complex::<i8>{ re: 0, im: -18})
}
#[test]
fn complex_multiply() {
let num_one = Complex::<i8>{ re: 2, im: 9};
let num_two = Complex::<i8>{ re: 7, im: 3};
assert_eq!(num_one.mul(num_two), Complex::<i8>{ re: -13, im: 69})
}
#[test]
fn complex_add() {
let num_one = Complex::<i8>{ re: 2, im: 9};
let num_two = Complex::<i8>{ re: 7, im: -3};
assert_eq!(num_one.add(num_two), Complex::<i8>{ re: 9, im: 6})
}
#[test]
fn complex_sub() {
let num_one = Complex::<i8>{ re: 2, im: 9};
let num_two = Complex::<i8>{ re: 7, im: -3};
assert_eq!(num_one.sub(num_two), Complex::<i8>{ re: -5, im: 12})
}
#[test]
fn complex_abs() {
let num_one = Complex::<f32>{ re: 2f32, im: 9f32};
assert_eq!(num_one.abs_square(), 85f32)
}
#[test]
fn complex_abs_square_root() {
let num_one = Complex::<f32>{ re: 2f32, im: 9f32};
assert_eq!(num_one.abs(), 85f32.sqrt())
}
#[test]
fn scale_a_complex_number_with_f64_rhs() {
let num_one = Complex::<f64>{ re: 2f64, im: 9f64};
assert_eq!(5f64 * num_one, Complex::<f64>{ re: 10f64, im: 45f64})
}
#[test]
fn scale_a_complex_number_with_f64_lhs() {
let num_one = Complex::<f64>{ re: 2f64, im: 9f64};
assert_eq!(num_one * 5f64, Complex::<f64>{ re: 10f64, im: 45f64})
}
}