1use dashu_base::{EstimatedLog2, Gcd};
2use dashu_int::{IBig, UBig};
3
4pub struct Repr {
5 pub(crate) numerator: IBig,
6 pub(crate) denominator: UBig,
7}
8
9impl Repr {
10 pub fn reduce(self) -> Repr {
12 if self.numerator.is_zero() {
13 return Repr::zero();
14 }
15
16 let g = (&self.numerator).gcd(&self.denominator);
17 Repr {
18 numerator: self.numerator / &g,
19 denominator: self.denominator / g,
20 }
21 }
22
23 pub fn reduce_with_hint(self, hint: UBig) -> Repr {
26 if self.numerator.is_zero() {
27 return Repr::zero();
28 }
29
30 let g = hint.gcd(&self.numerator).gcd(&self.denominator);
31 Repr {
32 numerator: self.numerator / &g,
33 denominator: self.denominator / g,
34 }
35 }
36
37 pub fn reduce2(self) -> Repr {
39 if self.numerator.is_zero() {
40 return Repr::zero();
41 }
42
43 let n_zeros = self.numerator.trailing_zeros().unwrap_or_default();
44 let d_zeros = self.denominator.trailing_zeros().unwrap();
45 let zeros = n_zeros.min(d_zeros);
46
47 if zeros > 0 {
48 Repr {
49 numerator: self.numerator >> zeros,
50 denominator: self.denominator >> zeros,
51 }
52 } else {
53 self
54 }
55 }
56
57 #[inline]
58 pub const fn zero() -> Repr {
59 Repr {
60 numerator: IBig::ZERO,
61 denominator: UBig::ONE,
62 }
63 }
64 #[inline]
65 pub const fn one() -> Repr {
66 Repr {
67 numerator: IBig::ONE,
68 denominator: UBig::ONE,
69 }
70 }
71 #[inline]
72 pub const fn neg_one() -> Repr {
73 Repr {
74 numerator: IBig::NEG_ONE,
75 denominator: UBig::ONE,
76 }
77 }
78
79 #[rustversion::since(1.64)]
82 pub const unsafe fn from_static_words(
83 sign: dashu_base::Sign,
84 numerator_words: &'static [dashu_int::Word],
85 denominator_words: &'static [dashu_int::Word],
86 ) -> Self {
87 let numerator = IBig::from_static_words(sign, numerator_words);
88 let denominator = UBig::from_static_words(denominator_words);
89
90 let num_zeros = match numerator.trailing_zeros() {
92 Some(n) => n,
93 None => 0,
94 };
95 let den_zeros = match denominator.trailing_zeros() {
96 Some(n) => n,
97 None => 0,
98 };
99 assert!(!(num_zeros > 0 && den_zeros > 0));
100
101 Self {
102 numerator,
103 denominator,
104 }
105 }
106}
107
108impl Clone for Repr {
110 #[inline]
111 fn clone(&self) -> Self {
112 Self {
113 numerator: self.numerator.clone(),
114 denominator: self.denominator.clone(),
115 }
116 }
117
118 #[inline]
119 fn clone_from(&mut self, source: &Self) {
120 self.numerator.clone_from(&source.numerator);
121 self.denominator.clone_from(&source.denominator);
122 }
123}
124
125impl EstimatedLog2 for Repr {
126 #[inline]
127 fn log2_est(&self) -> f32 {
128 self.numerator.log2_est() - self.denominator.log2_est()
129 }
130
131 fn log2_bounds(&self) -> (f32, f32) {
132 let (n_lb, n_ub) = self.numerator.log2_bounds();
133 let (d_lb, d_ub) = self.denominator.log2_bounds();
134 (n_lb - d_ub, n_ub - d_lb)
135 }
136}