use cas_attrs::builtin;
use crate::consts::{I, TAU, TEN};
use crate::primitive::{complex, float};
use rug::{ops::Pow as _, Complex, Float};
macro_rules! simple {
($($name:ident $upname:ident; $doc:literal),* $(,)?) => {
$(
#[doc = $doc]
#[derive(Debug)]
pub struct $upname;
#[cfg_attr(feature = "numerical", builtin)]
impl $upname {
pub fn eval_static(n: Complex) -> Complex {
n.$name()
}
}
)*
};
}
#[derive(Debug)]
pub struct Scientific;
#[cfg_attr(feature = "numerical", builtin)]
impl Scientific {
pub fn eval_static(a: Complex, b: Complex) -> Complex {
a * complex(&*TEN).pow(b)
}
}
#[derive(Debug)]
pub struct Log;
#[cfg_attr(feature = "numerical", builtin)]
impl Log {
pub fn eval_static(n: Complex, base: Option<Complex>) -> Complex {
let base = base.unwrap_or(complex(&*TEN));
n.ln() / base.ln()
}
}
#[derive(Debug)]
pub struct Pow;
#[cfg_attr(feature = "numerical", builtin)]
impl Pow {
pub fn eval_static(x: Complex, y: Complex) -> Complex {
x.pow(y)
}
}
#[derive(Debug)]
pub struct Cbrt;
#[cfg_attr(feature = "numerical", builtin)]
impl Cbrt {
pub fn eval_static(n: Complex) -> Complex {
let one_third = float(3.0).recip();
if n.real().is_sign_positive() {
n.pow(one_third)
} else {
let (abs, arg) = (
complex(n.abs_ref()).into_real_imag().0,
n.arg().into_real_imag().0,
);
let lhs = abs.cbrt();
let rhs = complex(one_third * (arg + &*TAU) * &*I).exp();
lhs * rhs
}
}
}
#[derive(Debug)]
pub struct Root;
#[cfg_attr(feature = "numerical", builtin)]
impl Root {
pub fn eval_static(x: Complex, n: Complex) -> Complex {
x.pow(n.recip())
}
}
#[derive(Debug)]
pub struct Hypot;
#[cfg_attr(feature = "numerical", builtin)]
impl Hypot {
pub fn eval_static(a: Float, b: Float) -> Float {
a.hypot(&b)
}
}
simple! {
exp Exp; "The exponential function, `e ^ x`.",
ln Ln; "The natural logarithm, `ln(x)`.",
sqrt Sqrt; "The square root function, `sqrt(x)`.",
}