ospf_rust_math/algebra/ordinary/
powf.rs

1use 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}