1use std::{
2 cmp::Ordering,
3 fmt::Display,
4 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
5 str::FromStr,
6};
7
8use crate::{detail, Decimal};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct Fraction {
13 num: i128,
15
16 den: i128,
18}
19
20impl Fraction {
21 pub fn new() -> Self {
23 Self { num: 0, den: 1 }
24 }
25
26 pub fn abs(&self) -> Self {
28 Self {
29 num: self.num.abs(),
30 den: self.den,
31 }
32 }
33
34 pub fn numerator(&self) -> i128 {
36 self.num
37 }
38
39 pub fn denominator(&self) -> i128 {
41 self.den
42 }
43
44 pub fn as_decimal(&self) -> Decimal {
46 (*self).into()
47 }
48
49 pub fn gcd(a: Self, b: Self) -> Self {
51 detail::gcd(a.abs(), b.abs())
52 }
53
54 pub fn lcm(a: Self, b: Self) -> Self {
56 if a == 0.into() || b == 0.into() {
57 return Self::new();
58 }
59
60 (a * b).abs() / Self::gcd(a, b) }
62
63 fn from_integer<T: Into<i128>>(value: T) -> Self {
64 Self { num: value.into(), den: 1 }
65 }
66
67 fn from_ratio<T: Into<i128>>(num: T, den: T) -> Self {
68 let (mut num, mut den) = (num.into(), den.into());
69
70 detail::check_zero(den);
72
73 if den < 0 {
75 num = -num;
76 den = -den;
77 }
78
79 let gcd = detail::gcd(num.abs(), den.abs());
81 num /= gcd;
82 den /= gcd;
83
84 Self { num, den }
85 }
86
87 pub const MAX: Fraction = Fraction { num: i128::MAX, den: 1 };
88 pub const MIN: Fraction = Fraction { num: i128::MIN, den: 1 };
89 pub const EPSILON: Fraction = Fraction { num: 1, den: i128::MAX };
90}
91
92macro_rules! impl_from_integer {
97 ($($t:ty),+ $(,)?) => { $(
98 impl From<$t> for Fraction {
99 fn from(value: $t) -> Self {
100 Fraction::from_integer(value)
101 }
102 }
103
104 impl From<($t, $t)> for Fraction {
105 fn from(value: ($t, $t)) -> Self {
106 Fraction::from_ratio(value.0, value.1)
107 }
108 }
109 )+ };
110}
111
112impl_from_integer!(i8, i16, i32, i64, i128, u8, u16, u32, u64);
114
115impl From<f64> for Fraction {
116 fn from(value: f64) -> Self {
117 if !value.is_finite() {
118 panic!("Error: Invalid floating-point number.");
119 }
120
121 let int_part = value.floor();
122 let dec_part = value - int_part;
123 let precision = i128::pow(10, f64::DIGITS);
124
125 let gcd = detail::gcd((dec_part * (precision as f64)).round() as i128, precision);
126 let mut num = (dec_part * precision as f64).round() as i128 / gcd;
127 let den = precision / gcd;
128 num += int_part as i128 * den;
129
130 Self { num, den }
131 }
132}
133
134impl From<f32> for Fraction {
135 fn from(value: f32) -> Self {
136 Fraction::from(value as f64)
137 }
138}
139
140impl From<Decimal> for Fraction {
141 fn from(value: Decimal) -> Self {
142 value.as_fraction()
143 }
144}
145
146impl From<&str> for Fraction {
147 fn from(value: &str) -> Self {
148 Self::from_str(value).unwrap_or_else(|_| panic!("expect format `numerator/denominator` but got `{}`", value))
149 }
150}
151
152#[derive(Debug, PartialEq, Eq)]
153pub struct ParseFractionError;
154
155impl FromStr for Fraction {
156 type Err = ParseFractionError;
157
158 fn from_str(s: &str) -> Result<Self, Self::Err> {
159 let s = s.trim();
160 if let Ok(num) = s.parse() {
161 return Ok(Self { num, den: 1 });
162 }
163
164 let (num, den) = s.split_once('/').ok_or(ParseFractionError)?;
165
166 let num = num.parse::<i128>().map_err(|_| ParseFractionError)?;
167 let den = den.parse::<i128>().map_err(|_| ParseFractionError)?;
168
169 Ok(Self::from((num, den)))
170 }
171}
172
173impl Default for Fraction {
174 fn default() -> Self {
175 Self::new()
176 }
177}
178
179impl PartialOrd for Fraction {
184 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
185 Some(self.cmp(other))
186 }
187}
188
189impl Ord for Fraction {
190 fn cmp(&self, other: &Self) -> Ordering {
191 (self.num * other.den - self.den * other.num).cmp(&0)
196 }
197}
198
199impl Neg for Fraction {
200 type Output = Self;
201
202 fn neg(self) -> Self::Output {
203 Self { num: -self.num, den: self.den }
204 }
205}
206
207#[auto_impl_ops::auto_ops]
208impl Add for Fraction {
209 type Output = Self;
210
211 fn add(self, rhs: Self) -> Self::Output {
212 Self::from((self.num * rhs.den + self.den * rhs.num, self.den * rhs.den))
213 }
214}
215
216#[auto_impl_ops::auto_ops]
217impl Sub for Fraction {
218 type Output = Self;
219
220 fn sub(self, rhs: Self) -> Self::Output {
221 Self::from((self.num * rhs.den - self.den * rhs.num, self.den * rhs.den))
222 }
223}
224
225#[auto_impl_ops::auto_ops]
226impl Mul for Fraction {
227 type Output = Self;
228
229 fn mul(self, rhs: Self) -> Self::Output {
230 Self::from((self.num * rhs.num, self.den * rhs.den))
231 }
232}
233
234#[auto_impl_ops::auto_ops]
235impl Div for Fraction {
236 type Output = Self;
237
238 fn div(self, rhs: Self) -> Self::Output {
239 Self::from((self.num * rhs.den, self.den * rhs.num))
240 }
241}
242
243#[auto_impl_ops::auto_ops]
244impl Rem for Fraction {
245 type Output = Self;
246
247 fn rem(self, rhs: Self) -> Self::Output {
248 detail::check_zero(rhs.num);
249
250 Self::from(((self.num * rhs.den) % (rhs.num * self.den), self.den * rhs.den))
251 }
252}
253
254impl Display for Fraction {
259 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
260 if self.den == 1 {
261 write!(f, "{}", self.num)
262 } else {
263 write!(f, "{}/{}", self.num, self.den)
264 }
265 }
266}
267
268impl From<Fraction> for f64 {
273 fn from(value: Fraction) -> Self {
274 value.num as f64 / value.den as f64
275 }
276}
277
278impl From<Fraction> for f32 {
279 fn from(value: Fraction) -> Self {
280 value.num as f32 / value.den as f32
281 }
282}