#![deny(unconditional_recursion)]
use core::ops::Neg;
use num_traits::{Float, FloatConst, Num, NumCast};
use crate::Complex;
mod private {
use num_traits::{Float, FloatConst};
use crate::Complex;
pub trait Seal {}
impl<T> Seal for T where T: Float + FloatConst {}
impl<T: Float + FloatConst> Seal for Complex<T> {}
}
pub trait ComplexFloat: Num + NumCast + Copy + Neg<Output = Self> + private::Seal {
type Real: Float + FloatConst;
fn is_nan(self) -> bool;
fn is_infinite(self) -> bool;
fn is_finite(self) -> bool;
fn is_normal(self) -> bool;
fn recip(self) -> Self;
fn powi(self, exp: i32) -> Self;
fn powf(self, exp: Self::Real) -> Self;
fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real>;
fn sqrt(self) -> Self;
fn exp(self) -> Self;
fn exp2(self) -> Self;
fn expf(self, base: Self::Real) -> Self;
fn ln(self) -> Self;
fn log(self, base: Self::Real) -> Self;
fn log2(self) -> Self;
fn log10(self) -> Self;
fn cbrt(self) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
fn asin(self) -> Self;
fn acos(self) -> Self;
fn atan(self) -> Self;
fn sinh(self) -> Self;
fn cosh(self) -> Self;
fn tanh(self) -> Self;
fn asinh(self) -> Self;
fn acosh(self) -> Self;
fn atanh(self) -> Self;
fn re(self) -> Self::Real;
fn im(self) -> Self::Real;
fn abs(self) -> Self::Real;
fn l1_norm(&self) -> Self::Real;
fn arg(self) -> Self::Real;
fn conj(self) -> Self;
}
macro_rules! forward {
($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method(self $( , $arg : $ty )* ) -> $ret {
$base::$method(self $( , $arg )* )
}
)*};
}
macro_rules! forward_ref {
($( Self :: $method:ident ( & self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method(self $( , $arg : $ty )* ) -> $ret {
Self::$method(&self $( , $arg )* )
}
)*};
}
impl<T> ComplexFloat for T
where
T: Float + FloatConst,
{
type Real = T;
fn re(self) -> Self::Real {
self
}
fn im(self) -> Self::Real {
T::zero()
}
fn l1_norm(&self) -> Self::Real {
self.abs()
}
fn arg(self) -> Self::Real {
if self.is_nan() {
self
} else if self.is_sign_negative() {
T::PI()
} else {
T::zero()
}
}
fn powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real> {
Complex::new(self, T::zero()).powc(exp)
}
fn conj(self) -> Self {
self
}
fn expf(self, base: Self::Real) -> Self {
base.powf(self)
}
forward! {
Float::is_normal(self) -> bool;
Float::is_infinite(self) -> bool;
Float::is_finite(self) -> bool;
Float::is_nan(self) -> bool;
Float::recip(self) -> Self;
Float::powi(self, n: i32) -> Self;
Float::powf(self, f: Self) -> Self;
Float::sqrt(self) -> Self;
Float::cbrt(self) -> Self;
Float::exp(self) -> Self;
Float::exp2(self) -> Self;
Float::ln(self) -> Self;
Float::log(self, base: Self) -> Self;
Float::log2(self) -> Self;
Float::log10(self) -> Self;
Float::sin(self) -> Self;
Float::cos(self) -> Self;
Float::tan(self) -> Self;
Float::asin(self) -> Self;
Float::acos(self) -> Self;
Float::atan(self) -> Self;
Float::sinh(self) -> Self;
Float::cosh(self) -> Self;
Float::tanh(self) -> Self;
Float::asinh(self) -> Self;
Float::acosh(self) -> Self;
Float::atanh(self) -> Self;
Float::abs(self) -> Self;
}
}
impl<T: Float + FloatConst> ComplexFloat for Complex<T> {
type Real = T;
fn re(self) -> Self::Real {
self.re
}
fn im(self) -> Self::Real {
self.im
}
fn abs(self) -> Self::Real {
self.norm()
}
fn recip(self) -> Self {
self.finv()
}
fn l1_norm(&self) -> Self::Real {
self.re.abs() + self.im.abs()
}
fn is_nan(self) -> bool {
self.re.is_nan() || self.im.is_nan()
}
fn is_infinite(self) -> bool {
!self.is_nan() && (self.re.is_infinite() || self.im.is_infinite())
}
fn is_finite(self) -> bool {
self.re.is_finite() && self.im.is_finite()
}
fn is_normal(self) -> bool {
self.re.is_normal() && self.im.is_normal()
}
forward! {
Complex::arg(self) -> Self::Real;
Complex::powc(self, exp: Complex<Self::Real>) -> Complex<Self::Real>;
Complex::exp2(self) -> Self;
Complex::log(self, base: Self::Real) -> Self;
Complex::log2(self) -> Self;
Complex::log10(self) -> Self;
Complex::powf(self, f: Self::Real) -> Self;
Complex::sqrt(self) -> Self;
Complex::cbrt(self) -> Self;
Complex::exp(self) -> Self;
Complex::expf(self, base: Self::Real) -> Self;
Complex::ln(self) -> Self;
Complex::sin(self) -> Self;
Complex::cos(self) -> Self;
Complex::tan(self) -> Self;
Complex::asin(self) -> Self;
Complex::acos(self) -> Self;
Complex::atan(self) -> Self;
Complex::sinh(self) -> Self;
Complex::cosh(self) -> Self;
Complex::tanh(self) -> Self;
Complex::asinh(self) -> Self;
Complex::acosh(self) -> Self;
Complex::atanh(self) -> Self;
}
forward_ref! {
Self::powi(&self, n: i32) -> Self;
Self::conj(&self) -> Self;
}
}
#[cfg(test)]
mod test {
use crate::{
complex_float::ComplexFloat,
test::{_0_0i, _0_1i, _1_0i, _1_1i, float::close},
Complex,
};
use std::f64; fn closef(a: f64, b: f64) -> bool {
close_to_tolf(a, b, 1e-10)
}
fn close_to_tolf(a: f64, b: f64, tol: f64) -> bool {
let close = (a == b) || (a - b).abs() < tol;
if !close {
println!("{:?} != {:?}", a, b);
}
close
}
#[test]
fn test_exp2() {
assert!(close(ComplexFloat::exp2(_0_0i), _1_0i));
assert!(closef(<f64 as ComplexFloat>::exp2(0.), 1.));
}
#[test]
fn test_exp() {
assert!(close(ComplexFloat::exp(_0_0i), _1_0i));
assert!(closef(ComplexFloat::exp(0.), 1.));
}
#[test]
fn test_powi() {
assert!(close(ComplexFloat::powi(_0_1i, 4), _1_0i));
assert!(closef(ComplexFloat::powi(-1., 4), 1.));
}
#[test]
fn test_powz() {
assert!(close(ComplexFloat::powc(_1_0i, _0_1i), _1_0i));
assert!(close(ComplexFloat::powc(1., _0_1i), _1_0i));
}
#[test]
fn test_log2() {
assert!(close(ComplexFloat::log2(_1_0i), _0_0i));
assert!(closef(ComplexFloat::log2(1.), 0.));
}
#[test]
fn test_log10() {
assert!(close(ComplexFloat::log10(_1_0i), _0_0i));
assert!(closef(ComplexFloat::log10(1.), 0.));
}
#[test]
fn test_conj() {
assert_eq!(ComplexFloat::conj(_0_1i), Complex::new(0., -1.));
assert_eq!(ComplexFloat::conj(1.), 1.);
}
#[test]
fn test_is_nan() {
assert!(!ComplexFloat::is_nan(_1_0i));
assert!(!ComplexFloat::is_nan(1.));
assert!(ComplexFloat::is_nan(Complex::new(f64::NAN, f64::NAN)));
assert!(ComplexFloat::is_nan(f64::NAN));
}
#[test]
fn test_is_infinite() {
assert!(!ComplexFloat::is_infinite(_1_0i));
assert!(!ComplexFloat::is_infinite(1.));
assert!(ComplexFloat::is_infinite(Complex::new(
f64::INFINITY,
f64::INFINITY
)));
assert!(ComplexFloat::is_infinite(f64::INFINITY));
}
#[test]
fn test_is_finite() {
assert!(ComplexFloat::is_finite(_1_0i));
assert!(ComplexFloat::is_finite(1.));
assert!(!ComplexFloat::is_finite(Complex::new(
f64::INFINITY,
f64::INFINITY
)));
assert!(!ComplexFloat::is_finite(f64::INFINITY));
}
#[test]
fn test_is_normal() {
assert!(ComplexFloat::is_normal(_1_1i));
assert!(ComplexFloat::is_normal(1.));
assert!(!ComplexFloat::is_normal(Complex::new(
f64::INFINITY,
f64::INFINITY
)));
assert!(!ComplexFloat::is_normal(f64::INFINITY));
}
#[test]
fn test_arg() {
assert!(closef(
ComplexFloat::arg(_0_1i),
core::f64::consts::FRAC_PI_2
));
assert!(closef(ComplexFloat::arg(-1.), core::f64::consts::PI));
assert!(closef(ComplexFloat::arg(-0.), core::f64::consts::PI));
assert!(closef(ComplexFloat::arg(0.), 0.));
assert!(closef(ComplexFloat::arg(1.), 0.));
assert!(ComplexFloat::arg(f64::NAN).is_nan());
}
}