use core::fmt;
use core::ops::{Add, Div, Mul, Neg, Sub};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
pub struct Complex<T> {
pub re: T,
pub im: T,
}
impl<T> Complex<T> {
#[inline]
pub const fn new(re: T, im: T) -> Complex<T> {
Complex { re, im }
}
}
impl<T: Default> Complex<T> {
#[inline]
pub fn from_real(re: T) -> Complex<T> {
Complex {
re,
im: T::default(),
}
}
#[inline]
pub fn imaginary(one: T) -> Complex<T> {
Complex {
re: T::default(),
im: one,
}
}
}
impl<T: Default + PartialEq> Complex<T> {
#[inline]
pub fn is_zero(&self) -> bool {
self.re == T::default() && self.im == T::default()
}
#[inline]
pub fn is_real(&self) -> bool {
self.im == T::default()
}
}
impl<T> Complex<T>
where
T: Clone + Neg<Output = T>,
{
#[inline]
pub fn conj(&self) -> Complex<T> {
Complex {
re: self.re.clone(),
im: -self.im.clone(),
}
}
}
impl<T> Complex<T>
where
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
{
pub fn add(&self, rhs: &Complex<T>) -> Complex<T> {
Complex {
re: self.re.clone() + rhs.re.clone(),
im: self.im.clone() + rhs.im.clone(),
}
}
pub fn sub(&self, rhs: &Complex<T>) -> Complex<T> {
Complex {
re: self.re.clone() - rhs.re.clone(),
im: self.im.clone() - rhs.im.clone(),
}
}
pub fn mul(&self, rhs: &Complex<T>) -> Complex<T> {
let ac = self.re.clone() * rhs.re.clone();
let bd = self.im.clone() * rhs.im.clone();
let ad = self.re.clone() * rhs.im.clone();
let bc = self.im.clone() * rhs.re.clone();
Complex {
re: ac - bd,
im: ad + bc,
}
}
pub fn norm_sqr(&self) -> T {
self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone()
}
}
impl<T> Complex<T>
where
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Neg<Output = T>,
{
#[inline]
pub fn neg(&self) -> Complex<T> {
Complex {
re: -self.re.clone(),
im: -self.im.clone(),
}
}
}
impl<T> Complex<T>
where
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>,
{
pub fn div(&self, rhs: &Complex<T>) -> Complex<T> {
let denom = rhs.re.clone() * rhs.re.clone() + rhs.im.clone() * rhs.im.clone();
let re =
(self.re.clone() * rhs.re.clone() + self.im.clone() * rhs.im.clone()) / denom.clone();
let im = (self.im.clone() * rhs.re.clone() - self.re.clone() * rhs.im.clone()) / denom;
Complex { re, im }
}
}
impl<T> fmt::Display for Complex<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} + {}i", self.re, self.im)
}
}
macro_rules! complex_binop {
($tr:ident, $m:ident, $bound:path, $atr:ident, $am:ident) => {
impl<T> core::ops::$tr for Complex<T>
where
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + $bound,
{
type Output = Complex<T>;
#[inline]
fn $m(self, rhs: Complex<T>) -> Complex<T> {
Complex::$m(&self, &rhs)
}
}
impl<T> core::ops::$tr<&Complex<T>> for &Complex<T>
where
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + $bound,
{
type Output = Complex<T>;
#[inline]
fn $m(self, rhs: &Complex<T>) -> Complex<T> {
Complex::$m(self, rhs)
}
}
impl<T> core::ops::$atr for Complex<T>
where
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + $bound,
{
#[inline]
fn $am(&mut self, rhs: Complex<T>) {
*self = Complex::$m(self, &rhs);
}
}
};
}
complex_binop!(Add, add, Mul<Output = T>, AddAssign, add_assign);
complex_binop!(Sub, sub, Mul<Output = T>, SubAssign, sub_assign);
complex_binop!(Mul, mul, Mul<Output = T>, MulAssign, mul_assign);
complex_binop!(Div, div, Div<Output = T>, DivAssign, div_assign);
impl<T> core::ops::Neg for Complex<T>
where
T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Neg<Output = T>,
{
type Output = Complex<T>;
#[inline]
fn neg(self) -> Complex<T> {
Complex::neg(&self)
}
}