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