number_diff/functions/utils/
useful_functions.rs1use std::f64::{consts::E, NAN};
2
3use crate::{Elementary::*, Integrate, EULER_MASCHERONI};
4
5pub const COMPLEX_INFINITY: f64 = NAN;
12
13fn factorial_integer(numb: u128) -> u128 {
15 if numb == 0 {
16 1
17 } else {
18 let mut res: u128 = 1;
19 for i in 1..=numb {
20 res *= i;
21 }
22
23 res
24 }
25}
26
27pub fn gamma_function(z: f64) -> f64 {
30 let inner_funciton = Mul(
31 Pow(X.into(), Sub(Con(z).into(), Con(1.).into()).into()).into(),
32 Pow(Con(E).into(), Mul(X.into(), Con(-1.).into()).into()).into(),
33 );
34
35 if z.fract() == 0.0 {
37 inner_funciton
39 .integrate()
40 .set_lower_bound(0.)
41 .set_upper_bound(100.)
42 .set_precision(1000)
43 .evaluate()
44 .unwrap()
45 .round_to(0)
46 } else {
47 inner_funciton
48 .integrate()
49 .set_lower_bound(0.)
50 .set_upper_bound(100.)
51 .set_precision(100000)
52 .evaluate()
53 .unwrap()
54 }
55}
56
57pub fn polygamma_function(z: f64, m: usize) -> f64 {
60 if m == 0 {
61 digamma_function(z)
62 } else {
63 let inner_funciton = Pow(Log(Con(E).into(), X.into()).into(), Con(m as f64).into())
64 * Pow(X.into(), Con(z - 1.).into())
65 / (Con(1.) - X);
66
67 -inner_funciton
68 .integrate()
69 .set_lower_bound(1e-10)
70 .set_upper_bound(1. - 1e-10)
71 .set_precision(10)
72 .evaluate()
73 .unwrap()
74 }
75}
76
77pub fn digamma_function(z: f64) -> f64 {
80 let inner_funciton = (Con(1.) - Pow(X.into(), Con(z - 1.).into())) / (Con(1.) - X);
81
82 let integral_value = inner_funciton
83 .integrate()
84 .set_lower_bound(0.)
85 .set_upper_bound(1. - 1e-10)
86 .set_precision(1000)
87 .evaluate()
88 .unwrap();
89
90 integral_value - EULER_MASCHERONI
91}
92
93pub trait Factorial {
106 type Output;
107 fn factorial(&self) -> Self::Output;
108}
109
110macro_rules! impl_factorial_natural {
112 (for $($t:ty), +) => {
113 $(impl Factorial for $t {
114 type Output = u128;
115 fn factorial(&self) -> Self::Output {
116 factorial_integer(self.clone() as u128)
117 }
118 })*
119 };
120}
121impl_factorial_natural!(for u8, u16, u32, u64, u128, usize);
122
123macro_rules! impl_factorial_integer {
125 (for $($t:ty), +) => {
126 $(impl Factorial for $t {
127 type Output = f64;
128 fn factorial(&self) -> Self::Output {
129 if self.is_negative() {
130 NAN
133 } else {
134 factorial_integer(self.clone() as u128) as f64
135 }
136 }
137 })*
138 };
139}
140impl_factorial_integer!(for i8, i16, i32, i64, i128, isize);
141
142macro_rules! impl_factorial_float {
144 (for $($t:ty), +) => {
145 $(impl Factorial for $t {
146 type Output = Self;
147 fn factorial(&self) -> Self::Output{
148 gamma_function(*self as f64 + 1.) as Self
149 }
150 })*
151 }
152}
153impl_factorial_float!(for f32, f64);
154
155pub trait Round {
157 fn round_to(&mut self, decimal_places: u32) -> f64;
170
171 fn with_significant_figures(&mut self, digits: u64) -> Self;
181}
182
183macro_rules! impl_round_float {
184 (for $($t:ty), +) => {
185 $(impl Round for $t {
186 fn round_to(&mut self, decimal_places: u32) -> f64 {
187 let mut value = *self as f64;
188 value *= 10_usize.pow(decimal_places) as f64;
190 value = value.round();
192 value /= 10_usize.pow(decimal_places) as f64;
194 *self = value as Self;
196 value
197 }
198
199 fn with_significant_figures(&mut self, digits: u64) -> Self {
200 let value = if *self >= 0. {
201
202 let order = (*self).log10().trunc() as i32;
203 if digits as i32 <= order {
204 ((*self) as isize).with_significant_figures(digits) as Self
205 } else {
206 if *self >= 1. {
207 (*self * (10 as Self).powi((digits as i32 - order -1) as i32)).round() / (10 as Self).powi((digits as i32 - order -1) as i32)
208 } else {
209 (*self * (10 as Self).powi((digits as i32 - order) as i32)).round() / (10 as Self).powi((digits as i32 - order) as i32)
210 }
211 }
212 } else {
213 -1. *(*self *-1.).with_significant_figures(digits)
214 };
215
216 *self = value as Self;
217 value
218 }
219 })*
220 };
221}
222impl_round_float!(for f32, f64);
223
224macro_rules! impl_round_int {
225 (for $($t:ty), +) => {
226 $(impl Round for $t {
227 #[allow(unused_variables)]
228 fn round_to(&mut self, decimal_places: u32) -> f64 {
229 *self as f64
230 }
231 fn with_significant_figures(&mut self, digits: u64) -> Self {
232 let order = (*self).ilog10() as u64;
235 let new_value = ((*self) as f64 / 10_f64.powi((order - digits +1) as i32)).round() * 10_f64.powi((order - digits +1) as i32);
236 *self = new_value as Self;
238 *self
239 }
240 })*
241
242 };
243}
244impl_round_int!(for u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);