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
32fn repr_cmp_same_base<const B: Word, const ABS: bool>(
33 lhs: &Repr<B>,
34 rhs: &Repr<B>,
35 precision: Option<(usize, usize)>,
36) -> Ordering {
37 match (lhs.is_infinite(), rhs.is_infinite()) {
39 (true, true) => {
40 return if ABS {
41 Ordering::Equal
42 } else {
43 lhs.exponent.cmp(&rhs.exponent)
44 }
45 }
46 (false, true) => {
47 return match ABS || rhs.exponent >= 0 {
48 true => Ordering::Less,
49 false => Ordering::Greater,
50 }
51 }
52 (true, false) => {
53 return match ABS || lhs.exponent >= 0 {
54 true => Ordering::Greater,
55 false => Ordering::Less,
56 }
57 }
58 _ => {}
59 };
60
61 let sign = if ABS {
63 Sign::Positive
64 } else {
65 match (lhs.significand.sign(), rhs.significand.sign()) {
66 (Sign::Positive, Sign::Positive) => Sign::Positive,
67 (Sign::Positive, Sign::Negative) => return Ordering::Greater,
68 (Sign::Negative, Sign::Positive) => return Ordering::Less,
69 (Sign::Negative, Sign::Negative) => Sign::Negative,
70 }
71 };
72
73 match (lhs.significand.is_zero(), rhs.significand.is_zero()) {
75 (true, true) => return Ordering::Equal,
76 (true, false) => {
77 return Ordering::Less;
79 }
80 (false, true) => {
81 return Ordering::Greater;
83 }
84 _ => {}
85 }
86
87 let (lhs_exp, rhs_exp) = (lhs.exponent, rhs.exponent);
89 if let Some((lhs_prec, rhs_prec)) = precision {
90 if lhs_prec != 0 && rhs_prec != 0 {
92 if lhs_exp > rhs_exp.saturating_add(rhs_prec as isize) {
97 return sign * Ordering::Greater;
98 }
99 if rhs_exp > lhs_exp.saturating_add(lhs_prec as isize) {
100 return sign * Ordering::Less;
101 }
102 }
103 }
104
105 let (lhs_digits, rhs_digits) = (lhs.digits_ub(), rhs.digits_ub());
107 if lhs_exp > rhs_exp.saturating_add(rhs_digits as isize) {
108 return sign * Ordering::Greater;
109 }
110 if rhs_exp > lhs_exp.saturating_add(lhs_digits as isize) {
111 return sign * Ordering::Less;
112 }
113
114 let (lhs_signif, rhs_signif) = (&lhs.significand, &rhs.significand);
116 if ABS {
117 match lhs_exp.cmp(&rhs_exp) {
118 Ordering::Equal => lhs_signif.abs_cmp(rhs_signif),
119 Ordering::Greater => {
120 shl_digits::<B>(lhs_signif, (lhs_exp - rhs_exp) as usize).abs_cmp(rhs_signif)
121 }
122 Ordering::Less => {
123 lhs_signif.abs_cmp(&shl_digits::<B>(rhs_signif, (rhs_exp - lhs_exp) as usize))
124 }
125 }
126 } else {
127 match lhs_exp.cmp(&rhs_exp) {
128 Ordering::Equal => lhs_signif.cmp(rhs_signif),
129 Ordering::Greater => {
130 shl_digits::<B>(lhs_signif, (lhs_exp - rhs_exp) as usize).cmp(rhs_signif)
131 }
132 Ordering::Less => {
133 lhs_signif.cmp(&shl_digits::<B>(rhs_signif, (rhs_exp - lhs_exp) as usize))
134 }
135 }
136 }
137}
138
139impl<const B: Word> PartialOrd for Repr<B> {
140 #[inline]
141 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
142 Some(self.cmp(other))
143 }
144}
145
146impl<const B: Word> Ord for Repr<B> {
147 #[inline]
148 fn cmp(&self, other: &Self) -> Ordering {
149 repr_cmp_same_base::<B, false>(self, other, None)
150 }
151}
152
153impl<R1: Round, R2: Round, const B: Word> PartialOrd<FBig<R2, B>> for FBig<R1, B> {
154 #[inline]
155 fn partial_cmp(&self, other: &FBig<R2, B>) -> Option<Ordering> {
156 Some(repr_cmp_same_base::<B, false>(
157 &self.repr,
158 &other.repr,
159 Some((self.context.precision, other.context.precision)),
160 ))
161 }
162}
163
164impl<R: Round, const B: Word> Ord for FBig<R, B> {
165 #[inline]
166 fn cmp(&self, other: &Self) -> Ordering {
167 repr_cmp_same_base::<B, false>(
168 &self.repr,
169 &other.repr,
170 Some((self.context.precision, other.context.precision)),
171 )
172 }
173}
174
175impl<R: Round, const B: Word> AbsOrd for FBig<R, B> {
176 #[inline]
177 fn abs_cmp(&self, other: &Self) -> Ordering {
178 repr_cmp_same_base::<B, true>(
179 &self.repr,
180 &other.repr,
181 Some((self.context.precision, other.context.precision)),
182 )
183 }
184}
185
186pub(crate) fn repr_cmp_ubig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &UBig) -> Ordering {
187 if lhs.is_infinite() {
189 return if lhs.exponent > 0 || ABS {
190 Ordering::Greater
191 } else {
192 Ordering::Less
193 };
194 }
195
196 if !ABS && lhs.significand.sign() == Sign::Negative {
198 return Ordering::Less;
199 }
200
201 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
203 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
204 if lhs_lo > rhs_hi {
205 return Ordering::Greater;
206 }
207 if lhs_hi < rhs_lo {
208 return Ordering::Less;
209 }
210
211 let mut rhs: IBig = rhs.clone().into();
213 if lhs.exponent < 0 {
214 shl_digits_in_place::<B>(&mut rhs, (-lhs.exponent) as usize);
215 lhs.significand.cmp(&rhs)
216 } else {
217 shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(&rhs)
218 }
219}
220
221pub(crate) fn repr_cmp_ibig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &IBig) -> Ordering {
222 if lhs.is_infinite() {
224 return if lhs.exponent > 0 || ABS {
225 Ordering::Greater
226 } else {
227 Ordering::Less
228 };
229 }
230
231 let sign = if ABS {
233 Sign::Positive
234 } else {
235 match (lhs.significand.sign(), rhs.sign()) {
236 (Sign::Positive, Sign::Positive) => Sign::Positive,
237 (Sign::Positive, Sign::Negative) => return Ordering::Greater,
238 (Sign::Negative, Sign::Positive) => return Ordering::Less,
239 (Sign::Negative, Sign::Negative) => Sign::Negative,
240 }
241 };
242
243 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
245 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
246 if lhs_lo > rhs_hi {
247 return sign * Ordering::Greater;
248 }
249 if lhs_hi < rhs_lo {
250 return sign * Ordering::Less;
251 }
252
253 if lhs.exponent < 0 {
255 lhs.significand
256 .cmp(&shl_digits::<B>(rhs, (-lhs.exponent) as usize))
257 } else {
258 shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(rhs)
259 }
260}
261
262macro_rules! impl_abs_ord_with_method {
263 ($T:ty, $method:ident) => {
264 impl<const B: Word> AbsOrd<$T> for Repr<B> {
265 #[inline]
266 fn abs_cmp(&self, other: &$T) -> Ordering {
267 $method::<B, true>(self, other)
268 }
269 }
270 impl<const B: Word> AbsOrd<Repr<B>> for $T {
271 #[inline]
272 fn abs_cmp(&self, other: &Repr<B>) -> Ordering {
273 $method::<B, true>(other, self).reverse()
274 }
275 }
276 impl<R: Round, const B: Word> AbsOrd<$T> for FBig<R, B> {
277 #[inline]
278 fn abs_cmp(&self, other: &$T) -> Ordering {
279 $method::<B, true>(&self.repr, other)
280 }
281 }
282 impl<R: Round, const B: Word> AbsOrd<FBig<R, B>> for $T {
283 #[inline]
284 fn abs_cmp(&self, other: &FBig<R, B>) -> Ordering {
285 $method::<B, true>(&other.repr, self).reverse()
286 }
287 }
288 };
289}
290impl_abs_ord_with_method!(UBig, repr_cmp_ubig);
291impl_abs_ord_with_method!(IBig, repr_cmp_ibig);