ospf_rust_math/algebra/operator/algorithmic/
gcd_lcm.rs1use std::ops::{Div, Mul};
2
3use paste::paste;
4
5pub use crate::algebra::ordinary::gcd::*;
6
7pub trait GcdLcm: Sized {
8 type Output;
9
10 fn gcd(self, rhs: Self) -> Self::Output;
11 fn gcd_list(values: &[Self]) -> Self::Output;
12
13 fn lcm(self, rhs: Self) -> Self::Output;
14 fn lcm_list(values: &[Self]) -> Self::Output;
15
16 fn gcd_lcm(self, rhs: Self) -> (Self::Output, Self::Output);
17 fn gcd_lcm_list(values: &[Self]) -> (Self::Output, Self::Output);
18}
19
20pub fn gcd<T: GcdLcm>(lhs: T, rhs: T) -> T::Output {
21 lhs.gcd(rhs)
22}
23
24pub fn gcd_list<T: GcdLcm>(values: &[T]) -> T::Output {
25 T::gcd_list(values)
26}
27
28pub fn lcm<T: GcdLcm>(lhs: T, rhs: T) -> T::Output {
29 lhs.lcm(rhs)
30}
31
32pub fn lcm_list<T: GcdLcm>(values: &[T]) -> T::Output {
33 T::lcm_list(values)
34}
35
36pub fn gcd_lcm<T: GcdLcm>(lhs: T, rhs: T) -> (T::Output, T::Output) {
37 lhs.gcd_lcm(rhs)
38}
39
40pub fn gcd_lcm_list<T: GcdLcm>(values: &[T]) -> (T::Output, T::Output) {
41 T::gcd_lcm_list(values)
42}
43
44macro_rules! gcd_template {
45 ($type:ident, $gcd:ident) => {
46 impl GcdLcm for $type {
47 type Output = $type;
48
49 paste! {
50 fn gcd(self, rhs: $type) -> $type {
51 [<$gcd "_" $type>](self.clone(), rhs.clone())
52 }
53 }
54
55 fn gcd_list(values: &[$type]) -> $type {
56 todo!()
57 }
58
59 fn lcm(self, rhs: $type) -> $type {
60 let this_gcd = (&self).gcd(&rhs);
61 self * (rhs / this_gcd)
62 }
63
64 fn lcm_list(values: &[$type]) -> $type {
65 let this_gcd = Self::gcd_list(values);
66 let this_lcm = values
67 .iter()
68 .fold(this_gcd.clone(), |acc, x| acc * (x / &this_gcd));
69 this_lcm
70 }
71
72 fn gcd_lcm(self, rhs: $type) -> ($type, $type) {
73 let this_gcd = (&self).gcd(&rhs);
74 let this_lcm = self * (rhs / &this_gcd);
75 (this_gcd, this_lcm)
76 }
77
78 fn gcd_lcm_list(values: &[$type]) -> ($type, $type) {
79 let this_gcd = Self::gcd_list(values);
80 let this_lcm = values
81 .iter()
82 .fold(this_gcd.clone(), |acc, x| acc * (x / &this_gcd));
83 (this_gcd, this_lcm)
84 }
85 }
86
87 impl GcdLcm for &$type {
88 type Output = $type;
89
90 paste! {
91 fn gcd(self, rhs: &$type) -> $type {
92 [<$gcd _ $type>]((*self).clone(), (*rhs).clone())
93 }
94 }
95
96 fn gcd_list(values: &[Self]) -> $type {
97 todo!()
98 }
99
100 fn lcm(self, rhs: &$type) -> $type {
101 let this_gcd = self.gcd(rhs);
102 self * (rhs / &this_gcd)
103 }
104
105 fn lcm_list(values: &[Self]) -> $type {
106 let this_gcd = Self::gcd_list(values);
107 let this_lcm = values
108 .iter()
109 .fold(this_gcd.clone(), |acc, x| acc * (*x / &this_gcd));
110 this_lcm
111 }
112
113 fn gcd_lcm(self, rhs: &$type) -> ($type, $type) {
114 let this_gcd = self.gcd(rhs);
115 let this_lcm = self * (rhs / &this_gcd);
116 (this_gcd, this_lcm)
117 }
118
119 fn gcd_lcm_list(values: &[Self]) -> ($type, $type) {
120 let this_gcd = Self::gcd_list(values);
121 let this_lcm = values
122 .iter()
123 .fold(this_gcd.clone(), |acc, x| acc * (*x / &this_gcd));
124 (this_gcd, this_lcm)
125 }
126 }
127 };
128}
129
130macro_rules! small_gcd_template {
131 ($($type:ident)*) => ($(
132 gcd_template!($type, gcd_euclid);
133 )*)
134}
135small_gcd_template! { i8 i16 i32 u8 u16 u32 }
136
137macro_rules! floating_gcd_template {
138 ($($type:ident)*) => ($(
139 gcd_template!($type, gcd_euclid);
140 )*)
141}
142floating_gcd_template! { f32 f64 }
143
144macro_rules! big_gcd_template {
145 ($($type:ident)*) => ($(
146 gcd_template!($type, gcd_stein);
147 )*)
148}
149big_gcd_template! { i64 i128 isize u64 u128 usize }
150
151#[cfg(test)]
152mod tests {
153 use std::fmt::Debug;
154
155 use crate::algebra::concept::RealNumber;
156
157 use super::*;
158
159 fn test_real<T: RealNumber + GcdLcm<Output=T> + Debug>()
160 where
161 for<'a> &'a T: Mul<&'a T, Output = T> + GcdLcm<Output=T>,
162 {
163 assert_eq!(&(T::TWO.gcd(T::FIVE)), T::ONE);
164 assert_eq!(&(T::TEN.gcd(&(T::TWO * T::TWO))), T::TWO);
165 assert_eq!(&(T::TEN.gcd(&(T::FIVE * T::FIVE))), T::FIVE);
166
167 assert_eq!(&(T::TWO.lcm(T::FIVE)), T::TEN);
168 assert_eq!(&(T::TEN.lcm(&T::TWO)), T::TEN);
169 assert_eq!(&(T::TEN.lcm(&(T::TWO * T::TWO))), &(T::TEN * T::TWO));
170 assert_eq!(&(T::TEN.lcm(&T::FIVE)), T::TEN);
171 assert_eq!(&(T::TWO.lcm(&(T::FIVE * T::FIVE))), &(T::TEN * T::FIVE));
172 }
173
174 #[test]
175 fn test() {
176 test_real::<i8>();
177 test_real::<i16>();
178 test_real::<i32>();
179 test_real::<i64>();
180 test_real::<i128>();
181 test_real::<u8>();
182 test_real::<u16>();
183 test_real::<u32>();
184 test_real::<u64>();
185 test_real::<u128>();
186 test_real::<f32>();
187 test_real::<f64>();
188 }
189}