ospf_rust_math/algebra/operator/algorithmic/
reciprocal.rs1use 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}