ospf_rust_math/algebra/operator/algorithmic/
abs.rs1use std::ops::Neg;
2
3use crate::algebra::concept::{Arithmetic, SemiArithmetic, Signed, Unsigned};
4
5pub trait Abs {
6 type Output;
7
8 fn abs(self) -> Self::Output;
9}
10
11pub fn abs<T: Abs>(value: T) -> T::Output {
12 value.abs()
13}
14
15macro_rules! unsigned_abs_template {
16 ($($type:ident)*) => ($(
17 impl Abs for $type {
18 type Output = $type;
19
20 fn abs(self) -> $type {
21 self
22 }
23 }
24
25 impl Abs for &$type {
26 type Output = $type;
27
28 fn abs(self) -> $type {
29 self.clone()
30 }
31 }
32 )*)
33}
34unsigned_abs_template! { bool u8 u16 u32 u64 u128 usize }
35
36macro_rules! signed_abs_template {
37 ($($type:ident)*) => ($(
38 impl Abs for $type {
39 type Output = $type;
40
41 fn abs(self) -> $type {
42 if &self < $type::ZERO { -self } else { self }
43 }
44 }
45
46 impl Abs for &$type {
47 type Output = $type;
48
49 fn abs(self) -> $type {
50 if self < $type::ZERO { -self } else { *self }
51 }
52 }
53 )*)
54}
55signed_abs_template! { i8 i16 i32 i64 i128 isize f32 f64 }
56
57#[cfg(test)]
58mod tests {
59 use std::fmt::Debug;
60 use std::ops::Add;
61
62 use crate::algebra::concept::{Bounded, FloatingNumber, IntegerNumber, UIntegerNumber};
63
64 use super::*;
65
66 fn test_bounded<T: Arithmetic + Bounded + Abs<Output = T> + Debug>()
67 where
68 for<'a> &'a T: Abs<Output = T>,
69 {
70 assert_eq!(&(T::ZERO.clone().abs()), T::ZERO);
71 assert_eq!(&(T::ZERO.abs()), T::ZERO);
72 assert_eq!(&abs(T::ZERO.clone()), T::ZERO);
73 assert_eq!(&abs(T::ZERO), T::ZERO);
74
75 assert_eq!(&(T::POSITIVE_MINIMUM.clone()).abs(), T::POSITIVE_MINIMUM);
76 assert_eq!(&(T::POSITIVE_MINIMUM.abs()), T::POSITIVE_MINIMUM);
77 assert_eq!(&abs(T::POSITIVE_MINIMUM.clone()), T::POSITIVE_MINIMUM);
78 assert_eq!(&abs(T::POSITIVE_MINIMUM), T::POSITIVE_MINIMUM);
79
80 assert_eq!(&T::MAXIMUM.as_ref().map(|x| x.clone().abs()), T::MAXIMUM);
81 assert_eq!(&T::MAXIMUM.as_ref().map(|x| x.abs()), T::MAXIMUM);
82 assert_eq!(&T::MAXIMUM.as_ref().map(|x| abs(x.clone())), T::MAXIMUM);
83 assert_eq!(&T::MAXIMUM.as_ref().map(|x| abs(x)), T::MAXIMUM);
84 }
85
86 fn test_signed<T: Arithmetic + Bounded + Signed + Abs<Output = T> + Debug>()
87 where
88 for<'a> &'a T: Neg<Output = T> + Abs<Output = T>,
89 {
90 test_bounded::<T>();
91
92 assert_eq!(&(-T::POSITIVE_MINIMUM).abs(), T::POSITIVE_MINIMUM);
93 assert_eq!(&(&-T::POSITIVE_MINIMUM).abs(), T::POSITIVE_MINIMUM);
94 assert_eq!(&abs(-T::POSITIVE_MINIMUM), T::POSITIVE_MINIMUM);
95 assert_eq!(&abs(&-T::POSITIVE_MINIMUM), T::POSITIVE_MINIMUM);
96 }
97
98 fn test_int<T: IntegerNumber + Abs<Output = T> + Debug>()
99 where
100 for<'a> &'a T: Add<Output = T> + Neg<Output = T> + Abs<Output = T>,
101 {
102 test_signed::<T>();
103
104 assert_eq!(&T::MINIMUM.as_ref().map(|x| (x + T::ONE).abs()), T::MAXIMUM);
105 assert_eq!(
106 &T::MINIMUM.as_ref().map(|x| (&(x + T::ONE)).abs()),
107 T::MAXIMUM
108 );
109 assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(x + T::ONE)), T::MAXIMUM);
110 assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(&(x + T::ONE))), T::MAXIMUM);
111 }
112
113 fn test_uint<T: UIntegerNumber + Abs<Output = T> + Debug>()
114 where
115 for<'a> &'a T: Abs<Output = T>,
116 {
117 test_bounded::<T>();
118 }
119
120 fn test_flt<T: FloatingNumber + Abs<Output = T> + Debug>()
121 where
122 for<'a> &'a T: Neg<Output = T> + Abs<Output = T>,
123 {
124 test_signed::<T>();
125
126 assert_eq!(&T::MINIMUM.as_ref().map(|x| x.clone().abs()), T::MAXIMUM);
127 assert_eq!(&T::MINIMUM.as_ref().map(|x| x.abs()), T::MAXIMUM);
128 assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(x.clone())), T::MAXIMUM);
129 assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(x)), T::MAXIMUM);
130 }
131
132 #[test]
133 fn test() {
134 test_int::<i8>();
135 test_int::<i16>();
136 test_int::<i32>();
137 test_int::<i64>();
138 test_int::<i128>();
139 test_uint::<u8>();
140 test_uint::<u16>();
141 test_uint::<u32>();
142 test_uint::<u64>();
143 test_uint::<u128>();
144 test_flt::<f32>();
145 test_flt::<f64>();
146 }
147}