use crate::algebra::abstr::One;
use crate::algebra::abstr::{Complex, Real};
use crate::elementary::exponential::Exponential;
use crate::elementary::power::Power;
pub trait Trigonometry {
fn pi() -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
fn cot(self) -> Self;
fn sec(self) -> Self;
fn csc(self) -> Self;
fn arcsin(self) -> Self;
fn arccos(self) -> Self;
fn arctan(self) -> Self;
fn arctan2(self, other: Self) -> Self;
fn arccot(self) -> Self;
fn arcsec(self) -> Self;
fn arccsc(self) -> Self;
}
macro_rules! trigonometry_impl {
($t:ty, $pi: expr) => {
impl Trigonometry for $t {
fn pi() -> Self {
$pi
}
fn sin(self) -> Self {
self.sin()
}
fn cos(self) -> Self {
self.cos()
}
fn tan(self) -> Self {
self.tan()
}
fn cot(self) -> Self {
1.0 / self.tan()
}
fn sec(self) -> Self {
1.0 / self.cos()
}
fn csc(self) -> Self {
1.0 / self.sin()
}
fn arcsin(self) -> Self {
if self.abs() > 1.0 {
panic!();
}
self.asin()
}
fn arccos(self) -> Self {
if self.abs() > 1.0 {
panic!();
}
self.acos()
}
fn arctan(self) -> Self {
self.atan()
}
fn arctan2(self, other: Self) -> Self {
self.atan2(other)
}
fn arccot(self) -> Self {
if self == 0.0 {
return 0.0;
}
if self > 0.0 {
(1.0 / self).atan()
} else {
(1.0 / self).atan()
}
}
fn arcsec(self) -> Self {
(1.0 / self).acos()
}
fn arccsc(self) -> Self {
(1.0 / self).asin()
}
}
};
}
trigonometry_impl!(f32, std::f32::consts::PI);
trigonometry_impl!(f64, std::f64::consts::PI);
impl<T> Trigonometry for Complex<T>
where
T: Real,
{
fn pi() -> Self {
Complex {
re: T::pi(),
im: T::zero(),
}
}
fn sin(self) -> Self {
let a: Complex<T> = Complex::new(-self.im, self.re);
let b: Complex<T> = Complex::new(self.im, -self.re);
let c: Complex<T> = Complex::new(T::zero(), T::one() + T::one());
(a.exp() - b.exp()) / c
}
fn cos(self) -> Self {
let a: Complex<T> = Complex::new(-self.im, self.re);
let b: Complex<T> = Complex::new(self.im, -self.re);
let c: Complex<T> = Complex::new(T::one() + T::one(), T::zero());
(a.exp() + b.exp()) / c
}
fn tan(self) -> Self {
self.sin() / self.cos()
}
fn cot(self) -> Self {
Complex::one() / self.tan()
}
fn sec(self) -> Self {
Complex::one() / self.cos()
}
fn csc(self) -> Self {
Complex::one() / self.sin()
}
fn arcsin(self) -> Self {
let mi: Complex<T> = Complex::new(T::zero(), -T::one());
let iz: Complex<T> = Complex::new(-self.im, self.re);
let exp: Complex<T> = Complex::new(T::one() / (T::one() + T::one()), T::zero());
mi * (iz + (Complex::one() - self * self).pow(exp)).ln()
}
fn arccos(self) -> Self {
Complex::new(T::pi() / (T::one() + T::one()), T::zero()) - self.arcsin()
}
fn arctan(self) -> Self {
let two: T = T::one() + T::one();
let re: T;
if self.re == T::zero() {
if self.im.abs() <= T::one() {
re = T::zero()
} else if self.im > T::zero() {
re = T::pi() / two;
} else {
re = -T::pi() / two;
}
} else if self.re > T::zero() {
re = (((self.re * self.re + self.im * self.im - T::one()) / (two * self.re)).arctan()
+ T::pi() / two)
/ two
} else {
re = (((self.re * self.re + self.im * self.im - T::one()) / (two * self.re)).arctan()
- T::pi() / two)
/ two
}
let im: T =
((two * self.im) / (self.re * self.re + self.im * self.im + T::one())).artanh() / two;
Complex::new(re, im)
}
fn arctan2(self, _other: Self) -> Self {
unimplemented!()
}
fn arccot(self) -> Self {
if self.re == T::zero() && (self.im == T::one() || self.im == -T::one()) {
panic!()
}
(Complex::one() / self).arctan()
}
fn arcsec(self) -> Self {
if self.im == T::zero()
&& (self.re == -T::one() || self.re == T::zero() || self.re == T::one())
{
panic!()
}
(Complex::one() / self).arccos()
}
fn arccsc(self) -> Self {
(Complex::one() / self).arcsin()
}
}