ospf_rust_math/algebra/operator/algorithmic/
log.rs

1use crate::algebra::*;
2
3pub trait Log<Base: FloatingNumber = Self>: Sized {
4    type Output;
5
6    fn log(self, base: &Base) -> Option<Self::Output>;
7
8    fn lg2(self) -> Option<Self::Output> {
9        self.log(Base::TWO)
10    }
11
12    fn lg(self) -> Option<Self::Output> {
13        self.log(Base::TEN)
14    }
15
16    fn ln(self) -> Option<Self::Output> {
17        self.log(Base::E)
18    }
19}
20
21pub fn log<Lhs: Log<Rhs>, Rhs: FloatingNumber>(lhs: Lhs, rhs: &Rhs) -> Option<Lhs::Output> {
22    lhs.log(&rhs)
23}
24
25pub fn lg2<Lhs: Log<Rhs>, Rhs: FloatingNumber>(lhs: Lhs) -> Option<Lhs::Output> {
26    lhs.lg2()
27}
28
29pub fn lg<Lhs: Log<Rhs>, Rhs: FloatingNumber>(lhs: Lhs) -> Option<Lhs::Output> {
30    lhs.lg()
31}
32
33pub fn ln<Lhs: Log<Rhs>, Rhs: FloatingNumber>(lhs: Lhs) -> Option<Lhs::Output> {
34    lhs.ln()
35}
36
37macro_rules! int_log_template {
38    ($($type:ident)*) => ($(
39        impl Log<f64> for $type {
40            type Output = f64;
41
42            fn log(self, base: &f64) -> Option<f64> {
43                Some((self as f64).log(*base))
44            }
45        }
46
47
48        impl Log<f64> for &$type {
49            type Output = f64;
50
51            fn log(self, base: &f64) -> Option<f64> {
52                Some((*self as f64).log(*base))
53            }
54        }
55    )*)
56}
57int_log_template! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
58
59macro_rules! floating_log_template {
60    ($($type:ident)*) => ($(
61        impl Log for $type {
62            type Output = $type;
63
64            fn log(self, base: &Self) -> Option<$type> {
65                Some(self.log(*base))
66            }
67        }
68
69        impl Log<$type> for &$type {
70            type Output = $type;
71
72            fn log(self, base: &$type) -> Option<$type> {
73                Some((*self).log(*base))
74            }
75        }
76    )*);
77}
78floating_log_template! { f32 f64 }
79
80#[cfg(test)]
81mod tests {
82    use std::fmt::Debug;
83
84    use crate::algebra::concept::{Integer, FloatingNumber};
85
86    use super::*;
87
88    fn test_int<T: Integer + Log<f64, Output = f64> + Debug>()
89    where
90            for<'a> &'a T: Log<f64, Output = f64>
91    {
92
93    }
94
95    fn test_flt<T: FloatingNumber + Log<T, Output = T> + Debug>()
96    where
97            for<'a> &'a T: Log<T, Output = T>
98    {
99        assert_eq!(&T::TWO.lg2().unwrap(), T::ONE);
100    }
101
102    #[test]
103    fn test() {
104        test_int::<u8>();
105        test_int::<u16>();
106        test_int::<u32>();
107        test_int::<u64>();
108        test_int::<u128>();
109        test_int::<i8>();
110        test_int::<i16>();
111        test_int::<i32>();
112        test_int::<i64>();
113        test_int::<i128>();
114        test_flt::<f32>();
115        test_flt::<f64>();
116    }
117}