1use core::cmp::Ordering;
2
3use dashu_base::{AbsOrd, EstimatedLog2, Sign};
4use dashu_int::{IBig, UBig};
5
6use crate::{
7 fbig::FBig,
8 repr::Repr,
9 repr::Word,
10 round::Round,
11 utils::{shl_digits, shl_digits_in_place},
12};
13
14impl<R1: Round, R2: Round, const B: Word> PartialEq<FBig<R2, B>> for FBig<R1, B> {
15 #[inline]
16 fn eq(&self, other: &FBig<R2, B>) -> bool {
17 match (self.repr.is_infinite(), other.repr.is_infinite()) {
18 (true, true) => !((self.repr.exponent >= 0) ^ (other.repr.exponent >= 0)),
20
21 (false, false) => self.repr == other.repr,
24
25 (_, _) => false,
27 }
28 }
29}
30impl<R: Round, const B: Word> Eq for FBig<R, B> {}
31
32pub(crate) fn repr_cmp_same_base<const B: Word, const ABS: bool>(
50 lhs: &Repr<B>,
51 rhs: &Repr<B>,
52 precision: Option<(usize, usize)>,
53) -> Ordering {
54 match (lhs.is_infinite(), rhs.is_infinite()) {
56 (true, true) => {
57 return if ABS {
58 Ordering::Equal
59 } else {
60 lhs.exponent.cmp(&rhs.exponent)
61 }
62 }
63 (false, true) => {
64 return match ABS || rhs.exponent >= 0 {
65 true => Ordering::Less,
66 false => Ordering::Greater,
67 }
68 }
69 (true, false) => {
70 return match ABS || lhs.exponent >= 0 {
71 true => Ordering::Greater,
72 false => Ordering::Less,
73 }
74 }
75 _ => {}
76 };
77
78 let sign = if ABS {
80 Sign::Positive
81 } else {
82 match (lhs.significand.sign(), rhs.significand.sign()) {
83 (Sign::Positive, Sign::Positive) => Sign::Positive,
84 (Sign::Positive, Sign::Negative) => return Ordering::Greater,
85 (Sign::Negative, Sign::Positive) => return Ordering::Less,
86 (Sign::Negative, Sign::Negative) => Sign::Negative,
87 }
88 };
89
90 match (lhs.significand.is_zero(), rhs.significand.is_zero()) {
92 (true, true) => return Ordering::Equal,
93 (true, false) => {
94 return Ordering::Less;
96 }
97 (false, true) => {
98 return Ordering::Greater;
100 }
101 _ => {}
102 }
103
104 let (lhs_exp, rhs_exp) = (lhs.exponent, rhs.exponent);
106 if let Some((lhs_prec, rhs_prec)) = precision {
107 if lhs_prec != 0 && rhs_prec != 0 {
109 if lhs_exp > rhs_exp.saturating_add(rhs_prec as isize) {
114 return sign * Ordering::Greater;
115 }
116 if rhs_exp > lhs_exp.saturating_add(lhs_prec as isize) {
117 return sign * Ordering::Less;
118 }
119 }
120 }
121
122 let (lhs_digits, rhs_digits) = (lhs.digits_ub(), rhs.digits_ub());
124 if lhs_exp > rhs_exp.saturating_add(rhs_digits as isize) {
125 return sign * Ordering::Greater;
126 }
127 if rhs_exp > lhs_exp.saturating_add(lhs_digits as isize) {
128 return sign * Ordering::Less;
129 }
130
131 let (lhs_signif, rhs_signif) = (&lhs.significand, &rhs.significand);
133 if ABS {
134 match lhs_exp.cmp(&rhs_exp) {
135 Ordering::Equal => lhs_signif.abs_cmp(rhs_signif),
136 Ordering::Greater => {
137 shl_digits::<B>(lhs_signif, (lhs_exp - rhs_exp) as usize).abs_cmp(rhs_signif)
138 }
139 Ordering::Less => {
140 lhs_signif.abs_cmp(&shl_digits::<B>(rhs_signif, (rhs_exp - lhs_exp) as usize))
141 }
142 }
143 } else {
144 match lhs_exp.cmp(&rhs_exp) {
145 Ordering::Equal => lhs_signif.cmp(rhs_signif),
146 Ordering::Greater => {
147 shl_digits::<B>(lhs_signif, (lhs_exp - rhs_exp) as usize).cmp(rhs_signif)
148 }
149 Ordering::Less => {
150 lhs_signif.cmp(&shl_digits::<B>(rhs_signif, (rhs_exp - lhs_exp) as usize))
151 }
152 }
153 }
154}
155
156impl<const B: Word> PartialOrd for Repr<B> {
157 #[inline]
158 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
159 Some(self.cmp(other))
160 }
161}
162
163impl<const B: Word> Ord for Repr<B> {
164 #[inline]
165 fn cmp(&self, other: &Self) -> Ordering {
166 repr_cmp_same_base::<B, false>(self, other, None)
167 }
168}
169
170impl<R1: Round, R2: Round, const B: Word> PartialOrd<FBig<R2, B>> for FBig<R1, B> {
171 #[inline]
172 fn partial_cmp(&self, other: &FBig<R2, B>) -> Option<Ordering> {
173 Some(repr_cmp_same_base::<B, false>(
174 &self.repr,
175 &other.repr,
176 Some((self.context.precision, other.context.precision)),
177 ))
178 }
179}
180
181impl<R: Round, const B: Word> Ord for FBig<R, B> {
182 #[inline]
183 fn cmp(&self, other: &Self) -> Ordering {
184 repr_cmp_same_base::<B, false>(
185 &self.repr,
186 &other.repr,
187 Some((self.context.precision, other.context.precision)),
188 )
189 }
190}
191
192impl<R: Round, const B: Word> AbsOrd for FBig<R, B> {
193 #[inline]
194 fn abs_cmp(&self, other: &Self) -> Ordering {
195 repr_cmp_same_base::<B, true>(
196 &self.repr,
197 &other.repr,
198 Some((self.context.precision, other.context.precision)),
199 )
200 }
201}
202
203pub(crate) fn repr_cmp_ubig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &UBig) -> Ordering {
204 if lhs.is_infinite() {
206 return if lhs.exponent > 0 || ABS {
207 Ordering::Greater
208 } else {
209 Ordering::Less
210 };
211 }
212
213 if !ABS && lhs.significand.sign() == Sign::Negative {
215 return Ordering::Less;
216 }
217
218 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
220 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
221 if lhs_lo > rhs_hi {
222 return Ordering::Greater;
223 }
224 if lhs_hi < rhs_lo {
225 return Ordering::Less;
226 }
227
228 let mut rhs: IBig = rhs.clone().into();
230 if lhs.exponent < 0 {
231 shl_digits_in_place::<B>(&mut rhs, (-lhs.exponent) as usize);
232 lhs.significand.cmp(&rhs)
233 } else {
234 shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(&rhs)
235 }
236}
237
238pub(crate) fn repr_cmp_ibig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &IBig) -> Ordering {
239 if lhs.is_infinite() {
241 return if lhs.exponent > 0 || ABS {
242 Ordering::Greater
243 } else {
244 Ordering::Less
245 };
246 }
247
248 let sign = if ABS {
250 Sign::Positive
251 } else {
252 match (lhs.significand.sign(), rhs.sign()) {
253 (Sign::Positive, Sign::Positive) => Sign::Positive,
254 (Sign::Positive, Sign::Negative) => return Ordering::Greater,
255 (Sign::Negative, Sign::Positive) => return Ordering::Less,
256 (Sign::Negative, Sign::Negative) => Sign::Negative,
257 }
258 };
259
260 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
262 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
263 if lhs_lo > rhs_hi {
264 return sign * Ordering::Greater;
265 }
266 if lhs_hi < rhs_lo {
267 return sign * Ordering::Less;
268 }
269
270 if lhs.exponent < 0 {
272 lhs.significand
273 .cmp(&shl_digits::<B>(rhs, (-lhs.exponent) as usize))
274 } else {
275 shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(rhs)
276 }
277}
278
279macro_rules! impl_abs_ord_with_method {
280 ($T:ty, $method:ident) => {
281 impl<const B: Word> AbsOrd<$T> for Repr<B> {
282 #[inline]
283 fn abs_cmp(&self, other: &$T) -> Ordering {
284 $method::<B, true>(self, other)
285 }
286 }
287 impl<const B: Word> AbsOrd<Repr<B>> for $T {
288 #[inline]
289 fn abs_cmp(&self, other: &Repr<B>) -> Ordering {
290 $method::<B, true>(other, self).reverse()
291 }
292 }
293 impl<R: Round, const B: Word> AbsOrd<$T> for FBig<R, B> {
294 #[inline]
295 fn abs_cmp(&self, other: &$T) -> Ordering {
296 $method::<B, true>(&self.repr, other)
297 }
298 }
299 impl<R: Round, const B: Word> AbsOrd<FBig<R, B>> for $T {
300 #[inline]
301 fn abs_cmp(&self, other: &FBig<R, B>) -> Ordering {
302 $method::<B, true>(&other.repr, self).reverse()
303 }
304 }
305 };
306}
307impl_abs_ord_with_method!(UBig, repr_cmp_ubig);
308impl_abs_ord_with_method!(IBig, repr_cmp_ibig);