pub mod elementary;
pub mod trigonometric;
pub mod hyperbolic;
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign};
use std::{fmt, cmp::Ordering};
pub use crate::traits::{Number, Signed, Zero, One, Tiny};
pub struct Complex<T> {
pub real: T,
pub imag: T,
}
pub type Cmplx = Complex<f64>;
impl<T> Complex<T> {
#[inline]
pub const fn new(real: T, imag: T) -> Self {
Complex { real, imag }
}
}
impl<T: Clone + Signed> Complex<T> {
#[inline]
pub fn conj(&self) -> Self {
Self::new(self.real.clone(), -self.imag.clone())
}
}
impl<T: Clone> Clone for Complex<T> {
#[inline]
fn clone(&self) -> Self {
Self::new(self.real.clone(), self.imag.clone())
}
}
impl<T: Clone + Signed> Neg for Complex<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self::Output {
Self::Output::new( -self.real, -self.imag )
}
}
impl<T: Clone + Number> Add<Complex<T>> for Complex<T> {
type Output = Self;
#[inline]
fn add(self, plus: Self) -> Self::Output {
Self::Output::new(self.real + plus.real, self.imag + plus.imag)
}
}
impl<T: Clone + Number> Sub<Complex<T>> for Complex<T> {
type Output = Self;
#[inline]
fn sub(self, minus: Self) -> Self::Output {
Self::Output::new(self.real - minus.real, self.imag - minus.imag)
}
}
impl<T: Clone + Number> Mul<Complex<T>> for Complex<T> {
type Output = Self;
#[inline]
fn mul(self, times: Self) -> Self::Output {
let real = self.real.clone() * times.real.clone() - self.imag.clone() * times.imag.clone();
let imag = self.real * times.imag + self.imag * times.real;
Self::Output::new( real, imag )
}
}
impl<T: Clone + Number> Div<Complex<T>> for Complex<T> {
type Output = Self;
#[inline]
fn div(self, divisor: Self) -> Self::Output {
let denominator = divisor.real.clone() * divisor.real.clone() + divisor.imag.clone() * divisor.imag.clone();
let real = self.real.clone() * divisor.real.clone() + self.imag.clone() * divisor.imag.clone();
let imag = self.imag * divisor.real - self.real * divisor.imag;
Self::Output::new( real / denominator.clone(), imag / denominator )
}
}
impl<T: Number> Add<T> for Complex<T> {
type Output = Complex<T>;
fn add(self, plus: T) -> Self::Output {
Self::Output::new( self.real + plus, self.imag )
}
}
impl<T: Number> Sub<T> for Complex<T> {
type Output = Complex<T>;
fn sub(self, minus: T) -> Self::Output {
Self::Output::new( self.real - minus, self.imag )
}
}
impl<T: Clone + Number> Mul<T> for Complex<T> {
type Output = Complex<T>;
fn mul(self, scalar: T) -> Self::Output {
Self::Output::new( self.real * scalar.clone(), self.imag * scalar )
}
}
impl Mul<Complex<f64>> for f64 {
type Output = Complex<f64>;
#[inline]
fn mul(self, complex: Complex<f64>) -> Self::Output {
complex * self
}
}
impl<T: Clone + Number> Div<T> for Complex<T> {
type Output = Complex<T>;
fn div(self, scalar: T) -> Self::Output {
Self::Output::new( self.real / scalar.clone(), self.imag / scalar )
}
}
impl<T: Number> AddAssign for Complex<T> {
fn add_assign(&mut self, rhs: Self) {
self.real += rhs.real;
self.imag += rhs.imag;
}
}
impl<T: Number> SubAssign for Complex<T> {
fn sub_assign(&mut self, rhs: Self) {
self.real -= rhs.real;
self.imag -= rhs.imag;
}
}
impl<T: Clone + Number> MulAssign for Complex<T> {
fn mul_assign(&mut self, rhs: Self) {
let a = self.real.clone();
self.real *= rhs.real.clone();
self.real -= self.imag.clone() * rhs.imag.clone();
self.imag *= rhs.real;
self.imag += a * rhs.imag;
}
}
impl<T: Clone + Number> DivAssign for Complex<T> {
fn div_assign(&mut self, rhs: Self) {
let a = self.real.clone();
let denominator = rhs.real.clone() * rhs.real.clone() + rhs.imag.clone() * rhs.imag.clone();
self.real *= rhs.real.clone();
self.real += self.imag.clone() * rhs.imag.clone();
self.real /= denominator.clone();
self.imag *= rhs.real;
self.imag -= a * rhs.imag;
self.imag /= denominator;
}
}
impl<T: Number> AddAssign<T> for Complex<T> {
fn add_assign(&mut self, rhs: T) {
self.real += rhs;
}
}
impl<T: Number> SubAssign<T> for Complex<T> {
fn sub_assign(&mut self, rhs: T) {
self.real -= rhs;
}
}
impl<T: Clone + Number> MulAssign<T> for Complex<T> {
fn mul_assign(&mut self, rhs: T) {
self.real *= rhs.clone();
self.imag *= rhs;
}
}
impl<T: Clone + Number> DivAssign<T> for Complex<T> {
fn div_assign(&mut self, rhs: T) {
self.real /= rhs.clone();
self.imag /= rhs;
}
}
impl<T: Clone + Number> Zero for Complex<T> {
fn zero() -> Self {
Self::new(Zero::zero(), Zero::zero())
}
}
impl<T: Clone + Number> One for Complex<T> {
fn one() -> Self {
Self::new(One::one(), Zero::zero())
}
}
impl<T: Clone + Number> Tiny for Complex<T> {
fn tiny() -> Self {
Self::new(T::tiny(), T::tiny())
}
}
impl<T: Clone + Number> PartialEq for Complex<T> {
fn eq(&self, other: &Complex<T>) -> bool {
self.real == other.real && self.imag == other.imag
}
}
impl<T: Clone + Number + std::cmp::PartialOrd> PartialOrd for Complex<T> {
fn partial_cmp(&self, other: &Complex<T>) -> Option<Ordering> {
if self.real != other.real {
self.real.partial_cmp( &other.real )
} else {
self.imag.partial_cmp( &other.imag )
}
}
}
impl<T: Clone + Number> Complex<T> {
#[inline]
pub fn abs_sqr(&self) -> T {
self.real.clone() * self.real.clone() + self.imag.clone() * self.imag.clone()
}
}
impl Complex::<f64> {
#[inline]
pub fn abs(&self) -> f64 {
f64::sqrt( self.abs_sqr() )
}
}
impl Complex::<f64> {
#[inline]
pub fn arg(&self) -> f64 {
self.imag.atan2(self.real)
}
}
impl<T> fmt::Display for Complex<T> where
T: fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "( {}, {} )", self.real, self.imag )
}
}
impl<T> fmt::Debug for Complex<T> where
T: fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "( {:?}, {:?} )", self.real, self.imag )
}
}
impl<T: Number + Clone> Number for Complex<T> {
}
impl Signed for Complex<f64> {
fn abs(&self) -> Self {
let real: f64 = self.abs();
let imag: f64 = 0.0;
Complex { real, imag }
}
}
impl Copy for Complex<f64> {
}