use std::f64::{consts::E, NAN};
use crate::{Elementary::*, Integrate, EULER_MASCHERONI};
pub const COMPLEX_INFINITY: f64 = NAN;
fn factorial_integer(numb: u128) -> u128 {
if numb == 0 {
1
} else {
let mut res: u128 = 1;
for i in 1..=numb {
res *= i;
}
res
}
}
pub fn gamma_function(z: f64) -> f64 {
let inner_funciton = Mul(
Pow(X.into(), Sub(Con(z).into(), Con(1.).into()).into()).into(),
Pow(Con(E).into(), Mul(X.into(), Con(-1.).into()).into()).into(),
);
if z.fract() == 0.0 {
inner_funciton
.integrate()
.set_lower_bound(0.)
.set_upper_bound(100.)
.set_precision(1000)
.evaluate()
.unwrap()
.round_to(0)
} else {
inner_funciton
.integrate()
.set_lower_bound(0.)
.set_upper_bound(100.)
.set_precision(100000)
.evaluate()
.unwrap()
}
}
pub fn polygamma_function(z: f64, m: usize) -> f64 {
if m == 0 {
digamma_function(z)
} else {
let inner_funciton = Pow(Log(Con(E).into(), X.into()).into(), Con(m as f64).into())
* Pow(X.into(), Con(z - 1.).into())
/ (Con(1.) - X);
-inner_funciton
.integrate()
.set_lower_bound(1e-10)
.set_upper_bound(1. - 1e-10)
.set_precision(10)
.evaluate()
.unwrap()
}
}
pub fn digamma_function(z: f64) -> f64 {
let inner_funciton = (Con(1.) - Pow(X.into(), Con(z - 1.).into())) / (Con(1.) - X);
let integral_value = inner_funciton
.integrate()
.set_lower_bound(0.)
.set_upper_bound(1. - 1e-10)
.set_precision(1000)
.evaluate()
.unwrap();
integral_value - EULER_MASCHERONI
}
pub trait Factorial {
type Output;
fn factorial(&self) -> Self::Output;
}
macro_rules! impl_factorial_natural {
(for $($t:ty), +) => {
$(impl Factorial for $t {
type Output = u128;
fn factorial(&self) -> Self::Output {
factorial_integer(self.clone() as u128)
}
})*
};
}
impl_factorial_natural!(for u8, u16, u32, u64, u128, usize);
macro_rules! impl_factorial_integer {
(for $($t:ty), +) => {
$(impl Factorial for $t {
type Output = f64;
fn factorial(&self) -> Self::Output {
if self.is_negative() {
NAN
} else {
factorial_integer(self.clone() as u128) as f64
}
}
})*
};
}
impl_factorial_integer!(for i8, i16, i32, i64, i128, isize);
macro_rules! impl_factorial_float {
(for $($t:ty), +) => {
$(impl Factorial for $t {
type Output = Self;
fn factorial(&self) -> Self::Output{
gamma_function(*self as f64 + 1.) as Self
}
})*
}
}
impl_factorial_float!(for f32, f64);
pub trait Round {
fn round_to(&mut self, decimal_places: u32) -> f64;
fn with_significant_figures(&mut self, digits: u64) -> Self;
}
macro_rules! impl_round_float {
(for $($t:ty), +) => {
$(impl Round for $t {
fn round_to(&mut self, decimal_places: u32) -> f64 {
let mut value = *self as f64;
value *= 10_usize.pow(decimal_places) as f64;
value = value.round();
value /= 10_usize.pow(decimal_places) as f64;
*self = value as Self;
value
}
fn with_significant_figures(&mut self, digits: u64) -> Self {
let value = if *self >= 0. {
let order = (*self).log10().trunc() as i32;
if digits as i32 <= order {
((*self) as isize).with_significant_figures(digits) as Self
} else {
if *self >= 1. {
(*self * (10 as Self).powi((digits as i32 - order -1) as i32)).round() / (10 as Self).powi((digits as i32 - order -1) as i32)
} else {
(*self * (10 as Self).powi((digits as i32 - order) as i32)).round() / (10 as Self).powi((digits as i32 - order) as i32)
}
}
} else {
-1. *(*self *-1.).with_significant_figures(digits)
};
*self = value as Self;
value
}
})*
};
}
impl_round_float!(for f32, f64);
macro_rules! impl_round_int {
(for $($t:ty), +) => {
$(impl Round for $t {
#[allow(unused_variables)]
fn round_to(&mut self, decimal_places: u32) -> f64 {
*self as f64
}
fn with_significant_figures(&mut self, digits: u64) -> Self {
let order = (*self).ilog10() as u64;
let new_value = ((*self) as f64 / 10_f64.powi((order - digits +1) as i32)).round() * 10_f64.powi((order - digits +1) as i32);
*self = new_value as Self;
*self
}
})*
};
}
impl_round_int!(for u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);