1use crate::{repr::Repr, RBig, Relaxed};
2use core::{
3 cmp::Ordering,
4 hash::{Hash, Hasher},
5};
6use dashu_base::{
7 AbsOrd, BitTest, EstimatedLog2,
8 Sign::{self, *},
9};
10use dashu_int::{IBig, UBig};
11
12fn repr_eq<const ABS: bool>(a: &Repr, b: &Repr) -> bool {
14 if !ABS && a.numerator.sign() != b.numerator.sign() {
16 return false;
17 }
18 if a.numerator.is_zero() {
19 return b.numerator.is_zero();
20 }
21
22 let n1d2_bits = a.numerator.bit_len() as isize + b.denominator.bit_len() as isize;
23 let n2d1_bits = b.numerator.bit_len() as isize + a.denominator.bit_len() as isize;
24 if n1d2_bits.abs_diff(n2d1_bits) > 1 {
25 return false;
26 }
27
28 let lhs = &a.numerator * &b.denominator;
30 let rhs = &b.numerator * &a.denominator;
31 lhs.abs_cmp(&rhs).is_eq()
32}
33
34impl PartialEq for Repr {
35 #[inline]
36 fn eq(&self, other: &Self) -> bool {
37 repr_eq::<false>(self, other)
38 }
39}
40impl Eq for Repr {}
41
42impl PartialEq for RBig {
43 #[inline]
44 fn eq(&self, other: &Self) -> bool {
45 self.0.numerator == other.0.numerator && self.0.denominator == other.0.denominator
47 }
48}
49impl Eq for RBig {}
50
51impl Hash for RBig {
54 #[inline]
55 fn hash<H: Hasher>(&self, state: &mut H) {
56 self.0.numerator.hash(state);
57 self.0.denominator.hash(state);
58 }
59}
60
61fn repr_cmp<const ABS: bool>(lhs: &Repr, rhs: &Repr) -> Ordering {
62 let negative = if ABS {
64 false
65 } else {
66 match (lhs.numerator.sign(), rhs.numerator.sign()) {
67 (Positive, Positive) => false,
68 (Positive, Negative) => return Ordering::Greater,
69 (Negative, Positive) => return Ordering::Less,
70 (Negative, Negative) => true,
71 }
72 };
73
74 if lhs.denominator.is_one() && rhs.denominator.is_one() {
76 return if ABS {
77 lhs.numerator.abs_cmp(&rhs.numerator)
78 } else {
79 lhs.numerator.cmp(&rhs.numerator)
80 };
81 }
82 match (lhs.numerator.is_zero(), rhs.numerator.is_zero()) {
83 (true, true) => return Ordering::Equal,
84 (true, false) => return Ordering::Less, (false, true) => return Ordering::Greater, _ => {}
87 };
88
89 let lhs_bits = lhs.numerator.bit_len() as isize - lhs.denominator.bit_len() as isize;
91 let rhs_bits = rhs.numerator.bit_len() as isize - rhs.denominator.bit_len() as isize;
92 if lhs_bits > rhs_bits + 1 {
93 return match negative {
94 false => Ordering::Greater,
95 true => Ordering::Less,
96 };
97 } else if rhs_bits < lhs_bits - 1 {
98 return match negative {
99 false => Ordering::Less,
100 true => Ordering::Greater,
101 };
102 }
103
104 let n1d2 = (&lhs.numerator) * (&rhs.denominator);
106 let n2d1 = (&rhs.numerator) * (&lhs.denominator);
107 if ABS {
108 n1d2.abs_cmp(&n2d1)
109 } else {
110 n1d2.cmp(&n2d1)
111 }
112}
113
114impl PartialOrd for Repr {
115 #[inline]
116 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
117 Some(self.cmp(other))
118 }
119}
120
121impl Ord for Repr {
122 #[inline]
123 fn cmp(&self, other: &Self) -> Ordering {
124 repr_cmp::<false>(self, other)
125 }
126}
127
128impl AbsOrd for Repr {
129 #[inline]
130 fn abs_cmp(&self, other: &Self) -> Ordering {
131 repr_cmp::<true>(self, other)
132 }
133}
134
135macro_rules! forward_abs_ord_both_to_repr {
136 ($t1:ty, $t2:ty) => {
137 impl AbsOrd<$t2> for $t1 {
138 #[inline]
139 fn abs_cmp(&self, other: &$t2) -> Ordering {
140 repr_cmp::<true>(&self.0, &other.0)
141 }
142 }
143 };
144}
145forward_abs_ord_both_to_repr!(RBig, RBig);
146forward_abs_ord_both_to_repr!(RBig, Relaxed);
147forward_abs_ord_both_to_repr!(Relaxed, RBig);
148forward_abs_ord_both_to_repr!(Relaxed, Relaxed);
149
150macro_rules! forward_abs_ord_to_repr {
151 ($R:ty, $T:ty) => {
152 impl AbsOrd<$T> for $R {
153 #[inline]
154 fn abs_cmp(&self, other: &$T) -> Ordering {
155 self.0.abs_cmp(other)
156 }
157 }
158 impl AbsOrd<$R> for $T {
159 #[inline]
160 fn abs_cmp(&self, other: &$R) -> Ordering {
161 other.0.abs_cmp(self).reverse()
162 }
163 }
164 };
165}
166
167pub(crate) fn repr_cmp_ubig<const ABS: bool>(lhs: &Repr, rhs: &UBig) -> Ordering {
168 if !ABS && lhs.numerator.sign() == Sign::Negative {
170 return Ordering::Less;
171 }
172
173 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
175 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
176 if lhs_lo > rhs_hi {
177 return Ordering::Greater;
178 }
179 if lhs_hi < rhs_lo {
180 return Ordering::Less;
181 }
182
183 lhs.numerator.abs_cmp(&(rhs * &lhs.denominator))
185}
186
187impl AbsOrd<UBig> for Repr {
188 #[inline]
189 fn abs_cmp(&self, other: &UBig) -> Ordering {
190 repr_cmp_ubig::<true>(self, other)
191 }
192}
193forward_abs_ord_to_repr!(RBig, UBig);
194forward_abs_ord_to_repr!(Relaxed, UBig);
195
196pub(crate) fn repr_cmp_ibig<const ABS: bool>(lhs: &Repr, rhs: &IBig) -> Ordering {
197 let sign = if ABS {
199 Sign::Positive
200 } else {
201 match (lhs.numerator.sign(), rhs.sign()) {
202 (Sign::Positive, Sign::Positive) => Sign::Positive,
203 (Sign::Positive, Sign::Negative) => return Ordering::Greater,
204 (Sign::Negative, Sign::Positive) => return Ordering::Less,
205 (Sign::Negative, Sign::Negative) => Sign::Negative,
206 }
207 };
208
209 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
211 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
212 if lhs_lo > rhs_hi {
213 return sign * Ordering::Greater;
214 }
215 if lhs_hi < rhs_lo {
216 return sign * Ordering::Less;
217 }
218
219 if ABS {
221 lhs.numerator.abs_cmp(&(rhs * &lhs.denominator))
222 } else {
223 lhs.numerator.cmp(&(rhs * &lhs.denominator))
224 }
225}
226
227impl AbsOrd<IBig> for Repr {
228 #[inline]
229 fn abs_cmp(&self, other: &IBig) -> Ordering {
230 repr_cmp_ibig::<true>(self, other)
231 }
232}
233forward_abs_ord_to_repr!(RBig, IBig);
234forward_abs_ord_to_repr!(Relaxed, IBig);
235
236#[cfg(feature = "dashu-float")]
237pub(crate) mod with_float {
238 use super::*;
239 use dashu_float::{round::Round, FBig, Repr as FloatRepr};
240 use dashu_int::Word;
241
242 pub(crate) fn repr_cmp_fbig<const B: Word, const ABS: bool>(
243 lhs: &Repr,
244 rhs: &FloatRepr<B>,
245 ) -> Ordering {
246 if rhs.is_infinite() {
248 return match ABS || rhs.exponent() > 0 {
249 true => Ordering::Less,
250 false => Ordering::Greater,
251 };
252 }
253
254 let sign = if ABS {
256 Sign::Positive
257 } else {
258 match (lhs.numerator.sign(), rhs.significand().sign()) {
259 (Sign::Positive, Sign::Positive) => Sign::Positive,
260 (Sign::Positive, Sign::Negative) => return Ordering::Greater,
261 (Sign::Negative, Sign::Positive) => return Ordering::Less,
262 (Sign::Negative, Sign::Negative) => Sign::Negative,
263 }
264 };
265
266 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
268 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
269 if lhs_lo > rhs_hi {
270 return sign * Ordering::Greater;
271 }
272 if lhs_hi < rhs_lo {
273 return sign * Ordering::Less;
274 }
275
276 let rhs_exp = rhs.exponent();
277
278 let (mut lhs, mut rhs) = (lhs.numerator.clone(), rhs.significand() * &lhs.denominator);
280 if rhs_exp < 0 {
281 let exp = -rhs_exp as usize;
282 if B.is_power_of_two() {
283 lhs <<= exp * B.trailing_zeros() as usize;
284 } else {
285 lhs *= UBig::from_word(B).pow(exp);
286 }
287 } else {
288 let exp = rhs_exp as usize;
289 if B.is_power_of_two() {
290 rhs <<= exp * B.trailing_zeros() as usize;
291 } else {
292 rhs *= UBig::from_word(B).pow(exp);
293 }
294 }
295
296 if ABS {
297 lhs.abs_cmp(&rhs)
298 } else {
299 lhs.cmp(&rhs)
300 }
301 }
302
303 impl<R: Round, const B: Word> AbsOrd<FBig<R, B>> for RBig {
304 #[inline]
305 fn abs_cmp(&self, other: &FBig<R, B>) -> Ordering {
306 repr_cmp_fbig::<B, true>(&self.0, other.repr())
307 }
308 }
309
310 impl<R: Round, const B: Word> AbsOrd<FBig<R, B>> for Relaxed {
311 #[inline]
312 fn abs_cmp(&self, other: &FBig<R, B>) -> Ordering {
313 repr_cmp_fbig::<B, true>(&self.0, other.repr())
314 }
315 }
316
317 impl<R: Round, const B: Word> AbsOrd<RBig> for FBig<R, B> {
318 #[inline]
319 fn abs_cmp(&self, other: &RBig) -> Ordering {
320 repr_cmp_fbig::<B, true>(&other.0, self.repr()).reverse()
321 }
322 }
323
324 impl<R: Round, const B: Word> AbsOrd<Relaxed> for FBig<R, B> {
325 #[inline]
326 fn abs_cmp(&self, other: &Relaxed) -> Ordering {
327 repr_cmp_fbig::<B, true>(&other.0, self.repr()).reverse()
328 }
329 }
330}