cp_library_rs/number_theory/
frac.rs

1//! 比較を実装した分数の実装
2
3use std::cmp::Ordering;
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
5
6use num::{Integer, One, Zero};
7use num_integer::gcd;
8
9/// 分数を表す構造体
10/// - `Frac(a, b)` := a / b
11#[derive(Debug, Clone, Copy)]
12pub struct Frac<T: Integer>(T, T);
13
14impl<T: Integer + Copy> Frac<T> {
15    pub fn new(a: T, b: T) -> Self {
16        assert!(!b.is_zero(), "denominator must be non-zero");
17        let (mut a, mut b) = (a, b);
18        if b < T::zero() {
19            a = T::zero() - a;
20            b = T::zero() - b;
21        }
22        let c = gcd(a, b);
23        Self(a / c, b / c)
24    }
25
26    /// 分子
27    pub fn numer(&self) -> T {
28        self.0
29    }
30
31    /// 分母
32    pub fn denom(&self) -> T {
33        self.1
34    }
35
36    /// 整数に変換する
37    pub fn as_integer(&self) -> Option<T> {
38        let &Self(a, b) = self;
39        (a % b == T::zero()).then_some(a / b)
40    }
41}
42
43impl<T> Zero for Frac<T>
44where
45    T: Integer + Copy,
46{
47    fn zero() -> Self {
48        Self(T::zero(), T::one())
49    }
50    fn is_zero(&self) -> bool {
51        !self.1.is_zero() && self.0.is_zero()
52    }
53}
54
55impl<T> One for Frac<T>
56where
57    T: Integer + Copy,
58{
59    fn one() -> Self {
60        Self(T::one(), T::one())
61    }
62    fn is_one(&self) -> bool
63    where
64        Self: PartialEq,
65    {
66        !self.1.is_zero() && self.0 == self.1
67    }
68}
69
70impl<T> From<T> for Frac<T>
71where
72    T: Integer + Copy,
73{
74    fn from(value: T) -> Self {
75        Self::new(value, T::one())
76    }
77}
78
79impl<T> Add for Frac<T>
80where
81    T: Integer + Copy,
82{
83    type Output = Self;
84    fn add(self, rhs: Self) -> Self::Output {
85        let Frac(a, b) = self;
86        let Frac(c, d) = rhs;
87        Self::new(a * d + c * b, b * d)
88    }
89}
90
91impl<T> Sub for Frac<T>
92where
93    T: Integer + Copy,
94{
95    type Output = Self;
96    fn sub(self, rhs: Self) -> Self::Output {
97        let Frac(a, b) = self;
98        let Frac(c, d) = rhs;
99        Self::new(a * d - c * b, b * d)
100    }
101}
102
103impl<T> Mul for Frac<T>
104where
105    T: Integer + Copy,
106{
107    type Output = Self;
108    fn mul(self, rhs: Self) -> Self::Output {
109        let Frac(a, b) = self;
110        let Frac(c, d) = rhs;
111        Self::new(a * c, b * d)
112    }
113}
114
115impl<T> Div for Frac<T>
116where
117    T: Integer + Copy,
118{
119    type Output = Self;
120    fn div(self, rhs: Self) -> Self::Output {
121        let Frac(a, b) = self;
122        let Frac(c, d) = rhs;
123        assert!(!c.is_zero(), "division by zero fraction");
124        Self::new(a * d, b * c)
125    }
126}
127
128impl<T> AddAssign for Frac<T>
129where
130    T: Integer + Copy,
131{
132    fn add_assign(&mut self, rhs: Self) {
133        *self = *self + rhs;
134    }
135}
136
137impl<T> SubAssign for Frac<T>
138where
139    T: Integer + Copy,
140{
141    fn sub_assign(&mut self, rhs: Self) {
142        *self = *self - rhs;
143    }
144}
145
146impl<T> MulAssign for Frac<T>
147where
148    T: Integer + Copy,
149{
150    fn mul_assign(&mut self, rhs: Self) {
151        *self = *self * rhs;
152    }
153}
154
155impl<T> DivAssign for Frac<T>
156where
157    T: Integer + Copy,
158{
159    fn div_assign(&mut self, rhs: Self) {
160        *self = *self / rhs;
161    }
162}
163
164impl<T> Neg for Frac<T>
165where
166    T: Integer + Copy + Neg<Output = T>,
167{
168    type Output = Self;
169    fn neg(self) -> Self::Output {
170        let Frac(a, b) = self;
171        Self::new(-a, b)
172    }
173}
174
175impl<T> Add<T> for Frac<T>
176where
177    T: Integer + Copy,
178{
179    type Output = Self;
180    fn add(self, rhs: T) -> Self::Output {
181        self + Self::from(rhs)
182    }
183}
184
185impl<T> Sub<T> for Frac<T>
186where
187    T: Integer + Copy,
188{
189    type Output = Self;
190    fn sub(self, rhs: T) -> Self::Output {
191        self - Self::from(rhs)
192    }
193}
194
195impl<T> Mul<T> for Frac<T>
196where
197    T: Integer + Copy,
198{
199    type Output = Self;
200    fn mul(self, rhs: T) -> Self::Output {
201        let Frac(a, b) = self;
202        Self::new(a * rhs, b)
203    }
204}
205
206impl<T> Div<T> for Frac<T>
207where
208    T: Integer + Copy,
209{
210    type Output = Self;
211    fn div(self, rhs: T) -> Self::Output {
212        assert!(!rhs.is_zero(), "division by zero scalar");
213        let Frac(a, b) = self;
214        Self::new(a, b * rhs)
215    }
216}
217
218impl<T> AddAssign<T> for Frac<T>
219where
220    T: Integer + Copy,
221{
222    fn add_assign(&mut self, rhs: T) {
223        *self = *self + rhs;
224    }
225}
226
227impl<T> SubAssign<T> for Frac<T>
228where
229    T: Integer + Copy,
230{
231    fn sub_assign(&mut self, rhs: T) {
232        *self = *self - rhs;
233    }
234}
235
236impl<T> MulAssign<T> for Frac<T>
237where
238    T: Integer + Copy,
239{
240    fn mul_assign(&mut self, rhs: T) {
241        *self = *self * rhs;
242    }
243}
244
245impl<T> DivAssign<T> for Frac<T>
246where
247    T: Integer + Copy,
248{
249    fn div_assign(&mut self, rhs: T) {
250        *self = *self / rhs;
251    }
252}
253
254impl<T> PartialEq for Frac<T>
255where
256    T: Integer + Copy,
257{
258    fn eq(&self, other: &Self) -> bool {
259        let &Frac(a1, b1) = self;
260        let &Frac(a2, b2) = other;
261        a1 * b2 == a2 * b1
262    }
263}
264
265impl<T> Eq for Frac<T>
266where
267    T: Integer + Copy,
268{
269    fn assert_receiver_is_total_eq(&self) {}
270}
271
272impl<T> PartialOrd for Frac<T>
273where
274    T: Integer + Copy,
275{
276    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
277        Some(self.cmp(other))
278    }
279}
280
281impl<T> Ord for Frac<T>
282where
283    T: Integer + Copy,
284{
285    fn cmp(&self, other: &Self) -> Ordering {
286        let &Frac(a1, b1) = self;
287        let &Frac(a2, b2) = other;
288        (a1 * b2).cmp(&(a2 * b1))
289    }
290}