concision_traits/math/
percentages.rs

1/*
2    Appellation: difference <module>
3    Created At: 2025.11.26:12:09:51
4    Contrib: @FL03
5*/
6/// The [`PercentChange`] trait establishes a binary operator for computing the percent change
7/// between two values where the caller is considered the original value.
8pub trait PercentChange<Rhs = Self> {
9    type Output;
10
11    fn percent_change(self, rhs: Rhs) -> Self::Output;
12}
13/// Compute the percentage difference between two values.
14/// The percentage difference is defined as:
15///
16/// ```math
17/// \text{PercentDifference}(x, y) = 2\cdot\frac{|x - y|}{|x| + |y|}
18/// ```
19pub trait PercentDiff<Rhs = Self> {
20    type Output;
21
22    fn percent_diff(self, rhs: Rhs) -> Self::Output;
23}
24
25/*
26 ************* Implementations *************
27*/
28use num_traits::{FromPrimitive, NumOps, Signed, Zero};
29
30impl<T> PercentDiff for T
31where
32    T: Copy + Signed + Zero + FromPrimitive + NumOps<T, T>,
33{
34    type Output = T;
35
36    fn percent_diff(self, rhs: T) -> Self::Output {
37        T::from_u8(2).unwrap() * (self - rhs).abs() / (self.abs() + rhs.abs())
38    }
39}
40
41impl<A, B, C> PercentChange<B> for A
42where
43    C: core::ops::Div<B, Output = C>,
44    for<'b> A: core::ops::Sub<&'b B, Output = C>,
45{
46    type Output = C;
47
48    fn percent_change(self, rhs: B) -> Self::Output {
49        (self - &rhs) / rhs
50    }
51}
52
53// macro_rules! impl_percent_change {
54//     ($($T:ty),* $(,)?) => {
55//         $(impl_percent_change! { @impl $T })*
56//     };
57//     (@impl $T:ty) => {
58//         impl PercentChange<$T> for $T {
59//             type Output = $T;
60
61//             fn percent_change(self, rhs: $T) -> Self::Output {
62//                 (self - rhs) / rhs
63//             }
64//         }
65//     };
66// }