ospf_rust_math/algebra/ordinary/
log.rs1use std::ops::{Mul, Sub};
2
3use paste::paste;
4
5use crate::algebra::concept::{Arithmetic, FloatingNumber, Precision, RealNumber, SemiArithmetic};
6use crate::algebra::operator::Reciprocal;
7
8pub fn ln<T: FloatingNumber>(x: &T) -> Option<T>
9where
10 for<'a> &'a T: Sub<Output = T> + Mul<Output = T> + Reciprocal<Output = T>,
11{
12 if x <= T::ZERO {
13 (*<T as RealNumber>::NAN).clone()
14 } else {
15 let frac_e = T::E.reciprocal().unwrap();
16
17 let mut val = (T::ZERO).clone();
18 let mut xp = x.clone();
19 if &xp < T::ONE {
20 while xp <= frac_e {
21 xp *= T::E;
22 val -= T::ONE;
23 }
24 } else if &xp > T::ONE {
25 while &xp >= T::E {
26 xp /= T::E;
27 val += T::ONE;
28 }
29 }
30 let mut base = &xp - T::ONE;
31 let mut signed = (*T::ONE).clone();
32 let mut i = (*T::ONE).clone();
33 loop {
34 let this_item = &signed * &base / &i;
35 val += this_item.clone();
36 base *= &xp - T::ONE;
37 signed = -signed;
38 i += T::ONE;
39
40 if &this_item <= &<T as Precision>::EPSILON {
41 break;
42 }
43 }
44 Some(val)
45 }
46}
47
48pub fn log<T: FloatingNumber>(nature: &T, x: &T) -> Option<T>
49where
50 for<'a> &'a T: Sub<Output = T> + Mul<Output = T> + Reciprocal<Output = T>,
51{
52 if let (Some(ln_nature), Some(ln_x)) = (ln(nature), ln(x)) {
53 Some(ln_x / ln_nature)
54 } else {
55 None
56 }
57}
58
59pub fn lg10<T: FloatingNumber>(x: &T) -> Option<T>
60where
61 for<'a> &'a T: Sub<Output = T> + Mul<Output = T> + Reciprocal<Output = T>,
62{
63 log(T::TEN, x)
64}
65
66pub fn lg2<T: FloatingNumber>(x: &T) -> Option<T>
67where
68 for<'a> &'a T: Sub<Output = T> + Mul<Output = T> + Reciprocal<Output = T>,
69{
70 log(T::TWO, x)
71}
72
73macro_rules! ln_template {
74 ($($type:ident)*) => ($(
75 paste! {
76 pub fn [<ln_ $type>](x: &$type) -> Option<$type> {
77 if x <= $type::ZERO {
78 (*<$type as RealNumber>::NAN).clone()
79 } else {
80 let frac_e = $type::E.reciprocal().unwrap();
81
82 let mut val = (*$type::ZERO).clone();
83 let mut xp = x.clone();
84 if &xp < $type::ONE {
85 while xp <= frac_e {
86 xp *= $type::E;
87 val -= $type::ONE;
88 }
89 } else if &xp > $type::ONE {
90 while &xp >= $type::E {
91 xp /= $type::E;
92 val += $type::ONE;
93 }
94 }
95 let mut base = &xp - $type::ONE;
96 let mut signed = (*$type::ONE).clone();
97 let mut i = (*$type::ONE).clone();
98 loop {
99 let this_item = &signed * &base / &i;
100 val += this_item.clone();
101 base *= &xp - $type::ONE;
102 signed = -signed;
103 i += $type::ONE;
104
105 if &this_item <= &<$type as Precision>::EPSILON {
106 break;
107 }
108 }
109 Some(val)
110 }
111 }
112 }
113 )*)
114}
115ln_template! { f32 f64 }
116
117macro_rules! log_template {
118 ($($type:ident)*) => ($(
119 paste! {
120 pub fn [<log_ $type>](nature: &$type, x: &$type) -> Option<$type> {
121 if let (Some(ln_nature), Some(ln_x)) = ([<ln_ $type>](nature), [<ln_ $type>](x)) {
122 Some(ln_x / ln_nature)
123 } else {
124 None
125 }
126 }
127
128 pub fn [<lg10_ $type>](x: &$type) -> Option<$type> {
129 [<log_ $type>]($type::TEN, x)
130 }
131
132 pub fn [<lg2_ $type>](x: &$type) -> Option<$type> {
133 [<log_ $type>]($type::TWO, x)
134 }
135 }
136 )*)
137}
138log_template! { f32 f64 }