factor_rs/
lib.rs

1//! List the prime factors of a number or fraction using the [`Fraction`] type. Uses the
2//! [`prime_factorization`](https://crates.io/crates/prime_factorization) library.
3//!
4//! # Examples
5//!
6//! Basic usage:
7//!
8//! ```
9//! # use factor_rs::*;
10//! let frac = Fraction::whole(84);
11//! let factors: Vec<Factor> = frac.factorize().collect();
12//!
13//! assert_eq!(factors, [
14//!     Factor::Prime(2, 2),
15//!     Factor::Prime(3, 1),
16//!     Factor::Prime(7, 1),
17//! ]);
18//! ```
19//!
20//! Factorize a fraction:
21//!
22//! ```
23//! # use factor_rs::*;
24//! let frac = Fraction::new(-1370, 56);
25//! let factors: Vec<Factor> = frac.factorize().collect();
26//!
27//! assert_eq!(factors, [
28//!     Factor::NegativeOne,
29//!     Factor::Prime(2, -2),
30//!     Factor::Prime(5, 1),
31//!     Factor::Prime(7, -1),
32//!     Factor::Prime(137, 1),
33//! ]);
34//! ```
35//!
36//! Reduce a fraction:
37//!
38//! ```
39//! # use factor_rs::*;
40//! let frac = Fraction::new(1200, 362);
41//! let reduced: Fraction = frac.factorize().product();
42//!
43//! assert_eq!(reduced, Fraction::new(600, 181));
44//! ```
45
46#![warn(missing_docs)]
47
48use std::{cmp::Ordering, fmt, iter, ops};
49use either::Either;
50use prime_factorization::Factorization;
51
52/// A fraction that can be factorized.
53#[derive(Debug, Copy, Clone, Eq)]
54pub struct Fraction
55{
56    /// The sign, where false is positive and true is negative. Fractions with a numerator of 0
57    /// ignore the sign when checking equality.
58    pub sign: bool,
59    /// The numerator.
60    pub num: u128,
61    /// The denominator.
62    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    /// The multiplicative base fraction, 1/1.
77    pub const ONE: Self = Fraction { sign: false, num: 1, denom: 1 };
78
79    /// The additive base fraction, 0/1.
80    pub const ZERO: Self = Fraction { sign: false, num: 0, denom: 0 };
81
82    /// The negative multiplicative base fraction, -1/1.
83    pub const NEG_ONE: Self = Fraction { sign: true, num: 1, denom: 1 };
84
85    /// The fraction that represents positive infinity, 1/0.
86    pub const ONE_OVER_ZERO: Self = Fraction { sign: false, num: 1, denom: 0 };
87
88    /// The fraction that represents an undefined value, 0/0.
89    pub const ZERO_OVER_ZERO: Self = Fraction { sign: false, num: 0, denom: 0 };
90
91    /// The fraction that represents negative infinity, -1/0.
92    pub const NEG_ONE_OVER_ZERO: Self = Fraction { sign: true, num: 1, denom: 0 };
93
94    /// Creates a new fraciton from a numerator and denominator.
95    ///
96    /// # Examples:
97    ///
98    /// Basic usage:
99    ///
100    /// ```
101    /// # use factor_rs::*;
102    /// let frac = Fraction::new(2, -5);
103    ///
104    /// assert_eq!(frac.sign, true);
105    /// assert_eq!(frac.num, 2);
106    /// assert_eq!(frac.denom, 5);
107    /// ```
108    pub fn new(num: impl Into<Fraction>, denom: impl Into<Fraction>) -> Self
109    {
110        num.into() / denom.into()
111    }
112
113    /// Creates a new fraction from a numerator.
114    ///
115    /// # Examples:
116    ///
117    /// Basic usage:
118    ///
119    /// ```
120    /// # use factor_rs::*;
121    /// let frac = Fraction::whole(36);
122    ///
123    /// assert_eq!(frac.sign, false);
124    /// assert_eq!(frac.num, 36);
125    /// assert_eq!(frac.denom, 1);
126    /// ```
127    pub fn whole(num: impl Into<Fraction>) -> Self { num.into() }
128
129    /// The multiplicative reciprocal of this fraction, created by swapping the numerator and the
130    /// denominator.
131    pub const fn recip(&self) -> Self
132    {
133        Fraction { sign: self.sign, num: self.denom, denom: self.num }
134    }
135
136    /// Breaks this fraction down into it's prime factors. The factors are always yielded in order
137    /// from lowest to highest, and no two factors with the same base will appear.
138    ///
139    /// # Examples
140    ///
141    /// Basic usage:
142    ///
143    /// ```
144    /// # use factor_rs::*;
145    /// let frac = Fraction::new(-120, 130);
146    /// let factors: Vec<Factor> = frac.factorize().collect();
147    ///
148    /// assert_eq!(factors, [
149    ///     Factor::NegativeOne,
150    ///     Factor::Prime(2, 2),
151    ///     Factor::Prime(3, 1),
152    ///     Factor::Prime(13, -1),
153    /// ]);
154    /// ```
155    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/// A prime factor of a fraction.
230#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
231pub enum Factor
232{
233    /// The negative multiplicative base, -1. Only a factor of negative fractions.
234    NegativeOne,
235    /// The additive base, 0. Only a factor if the fraction evaluates to 0.
236    Zero,
237    /// The multiplicative base, 1. Only a factor if the fraction evaluates to 1.
238    One,
239    /// A prime number with an exponent. Appears in most fractions.
240    Prime(
241        /// The base, which is always prime.
242        u128,
243        /// The exponent.
244        i8,
245    ),
246    /// Positive infinity, 1/0. Only a factor if the fraction involves a division by zero.
247    OneOverZero,
248    /// An undefined value, 0/0. Only a factor if the fraction evaluates to 0/0.
249    ZeroOverZero,
250}
251
252impl Factor
253{
254    /// Determines if this factor would be displayed with an exponent or not. For primes, returns
255    /// false if the exponent is 1 and true otherwise. Always returns false for other variants.
256    ///
257    /// # Examples
258    ///
259    /// Basic usage:
260    ///
261    /// ```
262    /// # use factor_rs::*;
263    /// assert!(!Factor::NegativeOne.has_exponent());
264    /// assert!(Factor::Prime(2, 2).has_exponent());
265    /// assert!(!Factor::OneOverZero.has_exponent());
266    /// ```
267    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}