ospf_rust_math/algebra/operator/algorithmic/
reciprocal.rs

1use std::ops::Div;
2
3use crate::algebra::concept::{Arithmetic, RealNumber};
4
5pub trait Reciprocal {
6    type Output;
7
8    fn reciprocal(self) -> Option<Self::Output>;
9}
10
11pub fn reciprocal<T: Reciprocal>(value: T) -> Option<T::Output> {
12    value.reciprocal()
13}
14
15macro_rules! int_reciprocal_template {
16    ($($type:ident)*) => ($(
17        impl Reciprocal for $type {
18            type Output = $type;
19
20            fn reciprocal(self) -> Option<$type> {
21                if self == 0 {
22                    <$type as RealNumber>::NAN.clone()
23                } else if self == 1 {
24                    Some(1)
25                } else if self == -1 {
26                    Some(-1)
27                } else {
28                    Some(0)
29                }
30            }
31        }
32
33        impl Reciprocal for &$type {
34            type Output = $type;
35
36            fn reciprocal(self) -> Option<$type> {
37                if self == &0 {
38                    <$type as RealNumber>::NAN.clone()
39                } else if self == &1 {
40                    Some(1)
41                } else if self == &-1 {
42                    Some(-1)
43                } else {
44                    Some(0)
45                }
46            }
47        }
48    )*)
49}
50int_reciprocal_template! { i8 i16 i32 i64 i128 isize }
51
52macro_rules! uint_reciprocal_template {
53    ($($type:ident)*) => ($(
54        impl Reciprocal for $type {
55            type Output = $type;
56
57            fn reciprocal(self) -> Option<$type> {
58                if self == 0 {
59                    <$type as RealNumber>::NAN.clone()
60                } else if self == 1 {
61                    Some(1)
62                } else {
63                    Some(0)
64                }
65            }
66        }
67
68        impl Reciprocal for &$type {
69            type Output = $type;
70
71            fn reciprocal(self) -> Option<$type> {
72                if self == &0 {
73                    <$type as RealNumber>::NAN.clone()
74                } else if self == &1 {
75                    Some(1)
76                } else {
77                    Some(0)
78                }
79            }
80        }
81    )*)
82}
83uint_reciprocal_template! { u8 u16 u32 u64 u128 usize }
84
85macro_rules! flt_reciprocal_template {
86    ($($type:ident)*) => ($(
87        impl Reciprocal for $type {
88            type Output = $type;
89
90            fn reciprocal(self) -> Option<$type> {
91                if self == 0. {
92                    return <$type as RealNumber>::NAN.clone();
93                } else {
94                    return Some(1. / self);
95                }
96            }
97        }
98
99        impl Reciprocal for &$type {
100            type Output = $type;
101
102            fn reciprocal(self) -> Option<$type> {
103                if self == &0. {
104                    return <$type as RealNumber>::NAN.clone();
105                } else {
106                    return Some(1. / self);
107                }
108            }
109        }
110    )*)
111}
112flt_reciprocal_template! { f32 f64 }
113
114#[cfg(test)]
115mod tests {
116    use std::fmt::Debug;
117    use std::ops::Neg;
118
119    use crate::algebra::concept::{FloatingNumber, Integer, IntegerNumber, UIntegerNumber};
120
121    use super::*;
122
123    fn test_integer<T: Integer + Reciprocal<Output = T> + Debug>()
124    where
125        for<'a> &'a T: Reciprocal<Output = T>,
126    {
127        assert_eq!(&(T::ZERO.clone().reciprocal()), T::NAN);
128        assert_eq!(&(T::ZERO.reciprocal()), T::NAN);
129        assert_eq!(&reciprocal(T::ZERO.clone()), T::NAN);
130        assert_eq!(&reciprocal(T::ZERO), T::NAN);
131
132        assert_eq!(T::ONE.clone().reciprocal(), Some(T::ONE.clone()));
133        assert_eq!(T::ONE.reciprocal(), Some(T::ONE.clone()));
134        assert_eq!(reciprocal(T::ONE.clone()), Some(T::ONE.clone()));
135        assert_eq!(reciprocal(T::ONE), Some(T::ONE.clone()));
136
137        assert_eq!(T::TWO.clone().reciprocal(), Some(T::ZERO.clone()));
138        assert_eq!(T::TWO.reciprocal(), Some(T::ZERO.clone()));
139        assert_eq!(reciprocal(T::TWO.clone()), Some(T::ZERO.clone()));
140        assert_eq!(reciprocal(T::TWO), Some(T::ZERO.clone()));
141    }
142
143    fn test_int<T: IntegerNumber + Reciprocal<Output = T> + Debug>()
144    where
145        for<'a> &'a T: Neg<Output = T> + Reciprocal<Output = T>,
146    {
147        test_integer::<T>();
148
149        assert_eq!((-T::ONE).reciprocal(), Some(-T::ONE.clone()));
150        assert_eq!((&-T::ONE).reciprocal(), Some(-T::ONE.clone()));
151        assert_eq!(reciprocal(-T::ONE), Some(-T::ONE.clone()));
152        assert_eq!(reciprocal(&-T::ONE), Some(-T::ONE.clone()));
153    }
154
155    fn test_uint<T: UIntegerNumber + Reciprocal<Output = T> + Debug>()
156    where
157        for<'a> &'a T: Reciprocal<Output = T>,
158    {
159        test_integer::<T>();
160    }
161
162    fn test_flt<T: FloatingNumber + Div<Output = T> + Reciprocal<Output = T> + Debug>()
163    where
164        for<'a> &'a T: Div<Output = T> + Neg<Output = T> + Reciprocal<Output = T>,
165    {
166        assert!(T::ZERO.reciprocal().unwrap().is_nan());
167        assert!((&T::ZERO).reciprocal().unwrap().is_nan());
168        assert!(reciprocal(T::ZERO.clone()).unwrap().is_nan());
169        assert!(reciprocal(T::ZERO).unwrap().is_nan());
170
171        assert_eq!(T::ONE.clone().reciprocal(), Some(T::ONE.clone()));
172        assert_eq!(T::ONE.reciprocal(), Some(T::ONE.clone()));
173        assert_eq!(reciprocal(T::ONE.clone()), Some(T::ONE.clone()));
174        assert_eq!(reciprocal(T::ONE), Some(T::ONE.clone()));
175
176        assert_eq!((-T::ONE).reciprocal(), Some(-T::ONE.clone()));
177        assert_eq!((&-T::ONE).reciprocal(), Some(-T::ONE.clone()));
178        assert_eq!(reciprocal(-T::ONE), Some(-T::ONE.clone()));
179        assert_eq!(reciprocal(&-T::ONE), Some(-T::ONE.clone()));
180
181        assert_eq!(T::TWO.clone().reciprocal(), Some(T::ONE / T::TWO));
182        assert_eq!(T::TWO.reciprocal(), Some(T::ONE / T::TWO));
183        assert_eq!(reciprocal(T::TWO.clone()), Some(T::ONE / T::TWO));
184        assert_eq!(reciprocal(T::TWO), Some(T::ONE / T::TWO));
185    }
186
187    #[test]
188    fn test() {
189        test_int::<i8>();
190        test_int::<i16>();
191        test_int::<i32>();
192        test_int::<i64>();
193        test_int::<i128>();
194        test_uint::<u8>();
195        test_uint::<u16>();
196        test_uint::<u32>();
197        test_uint::<u64>();
198        test_uint::<u128>();
199        test_flt::<f32>();
200        test_flt::<f64>();
201    }
202}