yui_core/abst/
euc_ring.rs1use std::ops::{Div, DivAssign, Rem, RemAssign};
10use crate::abst::{Ring, RingOps};
11
12pub trait EucRingOps<T = Self>:
15 RingOps<T> +
16 Div<T, Output = T> +
17 for<'a> Div<&'a T, Output = T> +
18 Rem<T, Output = T> +
19 for<'a> Rem<&'a T, Output = T> +
20{}
21
22pub trait EucRing:
28 Ring +
29 EucRingOps +
30 DivAssign +
31 for<'a> DivAssign<&'a Self> +
32 RemAssign +
33 for<'a> RemAssign<&'a Self>
34where
35 for<'a> &'a Self: EucRingOps<Self>,
36{
37 fn divides(&self, y: &Self) -> bool {
39 !self.is_zero() && (y % self).is_zero()
40 }
41
42 fn gcd(x: &Self, y: &Self) -> Self {
48 if x.is_zero() && y.is_zero() { return Self::zero() }
49 if x.divides(y) { return x.normalized() }
50 if y.divides(x) { return y.normalized() }
51
52 let (mut x, mut y) = (x.clone(), y.clone());
53
54 while !y.is_zero() {
55 let r = &x % &y;
56 (x, y) = (y, r);
57 }
58
59 x.into_normalized()
60 }
61
62 fn gcdx(x: &Self, y: &Self) -> (Self, Self, Self) {
67 if x.is_zero() && y.is_zero() { return (Self::zero(), Self::zero(), Self::zero()) }
68
69 if x.divides(y) {
71 let u = x.normalizing_unit();
72 return (x * &u, u, Self::zero())
73 }
74 if y.divides(x) {
75 let u = y.normalizing_unit();
76 return (y * &u, Self::zero(), u)
77 }
78
79 let (mut x, mut y) = (x.clone(), y.clone());
80 let (mut s0, mut s1) = (Self::one(), Self::zero());
81 let (mut t0, mut t1) = (Self::zero(), Self::one() );
82
83 while !y.is_zero() {
84 let q = &x / &y;
85 let r = &x % &y;
86
87 (x, y) = (y, r);
88 (s1, s0) = (s0 - &q * &s1, s1);
89 (t1, t0) = (t0 - &q * &t1, t1);
90 }
91
92 let (d, s, t) = (x, s0, t0);
93
94 let u = d.normalizing_unit();
95 match u.is_one() {
96 true => (d, s, t),
97 false => (d * &u, s * &u, t * &u)
98 }
99 }
100
101 fn lcm(x: &Self, y: &Self) -> Self {
103 if x.is_zero() || y.is_zero() { return Self::zero() }
104
105 let g = Self::gcd(x, y);
106 let m = x * (y / g);
107 m.into_normalized()
108 }
109}