1#![warn(missing_docs)]
47
48use std::{cmp::Ordering, fmt, iter, ops};
49use either::Either;
50use prime_factorization::Factorization;
51
52#[derive(Debug, Copy, Clone, Eq)]
54pub struct Fraction
55{
56 pub sign: bool,
59 pub num: u128,
61 pub denom: u128,
63}
64
65impl PartialEq for Fraction
66{
67 fn eq(&self, other: &Self) -> bool
68 {
69 if self.num == 0 { (self.num, self.denom) == (other.num, other.denom) }
70 else { (self.sign, self.num, self.denom) == (other.sign, other.num, other.denom) }
71 }
72}
73
74impl Fraction
75{
76 pub const ONE: Self = Fraction { sign: false, num: 1, denom: 1 };
78
79 pub const ZERO: Self = Fraction { sign: false, num: 0, denom: 0 };
81
82 pub const NEG_ONE: Self = Fraction { sign: true, num: 1, denom: 1 };
84
85 pub const ONE_OVER_ZERO: Self = Fraction { sign: false, num: 1, denom: 0 };
87
88 pub const ZERO_OVER_ZERO: Self = Fraction { sign: false, num: 0, denom: 0 };
90
91 pub const NEG_ONE_OVER_ZERO: Self = Fraction { sign: true, num: 1, denom: 0 };
93
94 pub fn new(num: impl Into<Fraction>, denom: impl Into<Fraction>) -> Self
109 {
110 num.into() / denom.into()
111 }
112
113 pub fn whole(num: impl Into<Fraction>) -> Self { num.into() }
128
129 pub const fn recip(&self) -> Self
132 {
133 Fraction { sign: self.sign, num: self.denom, denom: self.num }
134 }
135
136 pub fn factorize(&self) -> impl Iterator<Item = Factor>
156 {
157 match self
158 {
159 Fraction { num: 0, denom: 0, ..} => Either::Left(iter::once(Factor::ZeroOverZero)),
160 Fraction { num: 0, .. } => Either::Left(iter::once(Factor::Zero)),
161 Fraction { sign: false, num, denom } if num == denom =>
162 Either::Left(iter::once(Factor::One)),
163 Fraction { sign: true, num, denom } if num == denom =>
164 Either::Left(iter::once(Factor::NegativeOne)),
165 Fraction { .. } => Either::Right(
166 (if self.sign { Some(Factor::NegativeOne) } else { None })
167 .into_iter()
168 .chain(self.prime_factors().map(|(val, exp)| Factor::Prime(val, exp)))
169 .chain(if self.denom == 0 { Some(Factor::OneOverZero) } else { None })
170 ),
171 }
172 }
173
174 fn prime_factors(&self) -> impl Iterator<Item = (u128, i8)>
175 {
176 let mut num = Factorization::run(self.num)
177 .prime_factor_repr()
178 .into_iter()
179 .map(|(val, exp)| (val, exp as i8));
180
181 let mut denom = Factorization::run(self.denom)
182 .prime_factor_repr()
183 .into_iter()
184 .map(|(val, exp)| (val, -(exp as i8)));
185
186 let mut num_curr = num.next();
187 let mut denom_curr = denom.next();
188
189 iter::from_fn(move ||
190 {
191 let Some((num_val, num_exp)) = num_curr else
192 {
193 let res = denom_curr;
194 denom_curr = denom.next();
195 return res
196 };
197
198 let Some((denom_val, denom_exp)) = denom_curr else
199 {
200 let res = num_curr;
201 num_curr = num.next();
202 return res
203 };
204
205 match num_val.cmp(&denom_val)
206 {
207 Ordering::Less =>
208 {
209 num_curr = num.next();
210 Some((num_val, num_exp))
211 },
212 Ordering::Equal =>
213 {
214 num_curr = num.next();
215 denom_curr = denom.next();
216 Some((num_val, num_exp + denom_exp))
217 },
218 Ordering::Greater =>
219 {
220 denom_curr = denom.next();
221 Some((denom_val, denom_exp))
222 },
223 }
224 })
225 .filter(|(val, exp)| *exp != 0 && *val != 1 && *val != 0)
226 }
227}
228
229#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
231pub enum Factor
232{
233 NegativeOne,
235 Zero,
237 One,
239 Prime(
241 u128,
243 i8,
245 ),
246 OneOverZero,
248 ZeroOverZero,
250}
251
252impl Factor
253{
254 pub const fn has_exponent(&self) -> bool { matches!(self, Factor::Prime(_, ..=0 | 2..)) }
268}
269
270impl From<Factor> for Fraction
271{
272 fn from(fac: Factor) -> Self
273 {
274 match fac
275 {
276 Factor::NegativeOne => Fraction::NEG_ONE,
277 Factor::Zero => Fraction::ZERO,
278 Factor::One => Fraction::ONE,
279 Factor::Prime(val, exp @ 1..) => Fraction
280 {
281 sign: false,
282 num: num::pow(val, exp as usize),
283 denom: 1,
284 },
285 Factor::Prime(val, exp @ ..=-1) => Fraction
286 {
287 sign: false,
288 num: 1,
289 denom: num::pow(val, exp.unsigned_abs() as usize),
290 },
291 Factor::Prime(1.., 0) => Fraction::ONE,
292 Factor::Prime(0, 0) => Fraction::ZERO_OVER_ZERO,
293 Factor::OneOverZero => Fraction::ONE_OVER_ZERO,
294 Factor::ZeroOverZero => Fraction::ZERO_OVER_ZERO,
295 }
296 }
297}
298
299impl fmt::Display for Factor
300{
301 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
302 {
303 match self
304 {
305 Factor::NegativeOne => write!(f, "-1"),
306 Factor::Zero => write!(f, "0"),
307 Factor::One => write!(f, "1"),
308 Factor::Prime(val, exp) => if *exp == 1 { write!(f, "{val}") }
309 else { write!(f, "{val}^{exp}") },
310 Factor::OneOverZero => write!(f, "1/0"),
311 Factor::ZeroOverZero => write!(f, "0/0"),
312 }
313 }
314}
315
316impl fmt::Display for Fraction
317{
318 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
319 {
320 match self
321 {
322 Fraction { num: 0, denom: 0, .. } => write!(f, "0/0"),
323 Fraction { num: 0, .. } => write!(f, "0"),
324 Fraction { sign: false, denom: 0, .. } => write!(f, "1/0"),
325 Fraction { sign: true, denom: 0, .. } => write!(f, "-1/0"),
326 Fraction { sign: false, num, denom: 1 } => write!(f, "{num}"),
327 Fraction { sign: true, num, denom: 1 } => write!(f, "-{num}"),
328 Fraction { sign: false, num, denom } => write!(f, "{num}/{denom}"),
329 Fraction { sign: true, num, denom } => write!(f, "-{num}/{denom}"),
330 }
331 }
332}
333
334macro_rules! impl_from_ints
335{
336 ($int:ident + $uint:ident) =>
337 {
338 impl From<$int> for Fraction
339 {
340 fn from(num: $int) -> Self
341 {
342 Fraction { sign: num.is_negative(), num: num.unsigned_abs() as u128, denom: 1 }
343 }
344 }
345
346 impl From<$uint> for Fraction
347 {
348 fn from(num: $uint) -> Self
349 {
350 Fraction { sign: false, num: num as u128, denom: 1 }
351 }
352 }
353 };
354}
355
356impl_from_ints!(i8 + u8);
357impl_from_ints!(i16 + u16);
358impl_from_ints!(i32 + u32);
359impl_from_ints!(i64 + u64);
360impl_from_ints!(i128 + u128);
361
362impl ops::Neg for Fraction
363{
364 type Output = Fraction;
365 fn neg(self) -> Fraction { Fraction { sign: !self.sign, num: self.num, denom: self.denom } }
366}
367
368impl ops::Neg for &Fraction
369{
370 type Output = Fraction;
371 fn neg(self) -> Fraction { Fraction { sign: !self.sign, num: self.num, denom: self.denom } }
372}
373
374impl ops::Mul for Fraction
375{
376 type Output = Fraction;
377
378 fn mul(self, other: Self) -> Fraction
379 {
380 Fraction
381 {
382 sign: self.sign ^ other.sign,
383 num: self.num * other.num,
384 denom: self.denom * other.denom,
385 }
386 }
387}
388
389impl ops::Mul for &Fraction
390{
391 type Output = Fraction;
392
393 fn mul(self, other: Self) -> Fraction
394 {
395 Fraction
396 {
397 sign: self.sign ^ other.sign,
398 num: self.num * other.num,
399 denom: self.denom * other.denom,
400 }
401 }
402}
403
404impl ops::Div for Fraction
405{
406 type Output = Fraction;
407
408 fn div(self, other: Self) -> Fraction
409 {
410 Fraction
411 {
412 sign: self.sign ^ other.sign,
413 num: self.num * other.denom,
414 denom: self.denom * other.num,
415 }
416 }
417}
418
419impl ops::Div for &Fraction
420{
421 type Output = Fraction;
422
423 fn div(self, other: Self) -> Fraction
424 {
425 Fraction
426 {
427 sign: self.sign ^ other.sign,
428 num: self.num * other.denom,
429 denom: self.denom * other.num,
430 }
431 }
432}
433
434impl ops::MulAssign for Fraction
435{
436 fn mul_assign(&mut self, other: Self)
437 {
438 self.sign ^= other.sign;
439 self.num *= other.num;
440 self.denom *= other.denom;
441 }
442}
443
444impl ops::MulAssign<&Fraction> for Fraction
445{
446 fn mul_assign(&mut self, other: &Self)
447 {
448 self.sign ^= other.sign;
449 self.num *= other.num;
450 self.denom *= other.denom;
451 }
452}
453
454impl ops::DivAssign for Fraction
455{
456 fn div_assign(&mut self, other: Self)
457 {
458 self.sign ^= other.sign;
459 self.num *= other.denom;
460 self.denom *= other.num;
461 }
462}
463
464impl ops::DivAssign<&Fraction> for Fraction
465{
466 fn div_assign(&mut self, other: &Self)
467 {
468 self.sign ^= other.sign;
469 self.num *= other.denom;
470 self.denom *= other.num;
471 }
472}
473
474impl iter::Product for Fraction
475{
476 fn product<I: Iterator<Item = Self>>(iter: I) -> Self
477 {
478 iter.reduce(ops::Mul::mul).unwrap_or(Fraction::ONE)
479 }
480}
481
482impl iter::Product<Factor> for Fraction
483{
484 fn product<I: Iterator<Item = Factor>>(iter: I) -> Self
485 {
486 iter.map(Into::<Fraction>::into).product()
487 }
488}