ospf_rust_math/algebra/ordinary/
powf.rs1use std::ops::{Div, Mul, Sub};
2
3use paste::paste;
4
5use crate::algebra::concept::{Arithmetic, FloatingNumber, Precision, RealNumber};
6use crate::algebra::operator::Reciprocal;
7
8use super::ln;
9
10pub fn exp<T: FloatingNumber>(index: &T) -> T
11where
12 for<'a> &'a T: Div<Output = T>,
13{
14 let mut value = T::ONE.clone();
15 let mut base = index.clone();
16 let mut i = T::ONE.clone();
17 loop {
18 let this_item = &base / &i;
19 value += &this_item;
20 base *= index;
21 i += T::ONE;
22
23 if &this_item <= <T as Precision>::EPSILON {
24 break;
25 }
26 }
27 value
28}
29
30pub fn powf<T: FloatingNumber>(base: &T, index: &T) -> Option<T>
31where
32 for<'a> &'a T: Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Reciprocal<Output = T>,
33{
34 if let Some(ln_base) = ln(base) {
35 Some(exp(&(index * &ln_base)))
36 } else {
37 <T as RealNumber>::NAN.clone()
38 }
39}
40
41macro_rules! exp_template {
42 ($($type:ident)*) => ($(
43 paste! {
44 pub fn [<exp_ $type>](index: &$type) -> $type {
45 let mut value = (*$type::ONE).clone();
46 let mut base = index.clone();
47 let mut i = (*$type::ONE).clone();
48 loop {
49 let this_item = &base / &i;
50 value += &this_item;
51 base *= index;
52 i += $type::ONE;
53
54 if &this_item <= <$type as Precision>::EPSILON {
55 break;
56 }
57 }
58 value
59 }
60 }
61 )*)
62}
63exp_template! { f32 f64 }
64
65macro_rules! powf_template {
66 ($($type:ident)*) => ($(
67 paste! {
68 pub fn [<powf_ $type>](base: &$type, index: &$type) -> Option<$type> {
69 if let Some(ln_base) = [<ln_ $type>](base) {
70 Some([<exp_ $type>](&(index * &ln_base)))
71 } else {
72 (*<$type as RealNumber>::NAN).clone()
73 }
74 }
75 }
76 )*)
77}