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.is_zero(), rhs.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 + rhs_prec as isize {
93 return sign * Ordering::Greater;
94 }
95 if rhs_exp > lhs_exp + lhs_prec as isize {
96 return sign * Ordering::Less;
97 }
98 }
99 }
100
101 let (lhs_digits, rhs_digits) = (lhs.digits_ub(), rhs.digits_ub());
103 if lhs_exp > rhs_exp + rhs_digits as isize {
104 return sign * Ordering::Greater;
105 }
106 if rhs_exp > lhs_exp + lhs_digits as isize {
107 return sign * Ordering::Less;
108 }
109
110 let (lhs_signif, rhs_signif) = (&lhs.significand, &rhs.significand);
112 if ABS {
113 match lhs_exp.cmp(&rhs_exp) {
114 Ordering::Equal => lhs_signif.abs_cmp(rhs_signif),
115 Ordering::Greater => {
116 shl_digits::<B>(lhs_signif, (lhs_exp - rhs_exp) as usize).abs_cmp(rhs_signif)
117 }
118 Ordering::Less => {
119 lhs_signif.abs_cmp(&shl_digits::<B>(rhs_signif, (rhs_exp - lhs_exp) as usize))
120 }
121 }
122 } else {
123 match lhs_exp.cmp(&rhs_exp) {
124 Ordering::Equal => lhs_signif.cmp(rhs_signif),
125 Ordering::Greater => {
126 shl_digits::<B>(lhs_signif, (lhs_exp - rhs_exp) as usize).cmp(rhs_signif)
127 }
128 Ordering::Less => {
129 lhs_signif.cmp(&shl_digits::<B>(rhs_signif, (rhs_exp - lhs_exp) as usize))
130 }
131 }
132 }
133}
134
135impl<const B: Word> PartialOrd for Repr<B> {
136 #[inline]
137 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
138 Some(self.cmp(other))
139 }
140}
141
142impl<const B: Word> Ord for Repr<B> {
143 #[inline]
144 fn cmp(&self, other: &Self) -> Ordering {
145 repr_cmp_same_base::<B, false>(self, other, None)
146 }
147}
148
149impl<R1: Round, R2: Round, const B: Word> PartialOrd<FBig<R2, B>> for FBig<R1, B> {
150 #[inline]
151 fn partial_cmp(&self, other: &FBig<R2, B>) -> Option<Ordering> {
152 Some(repr_cmp_same_base::<B, false>(
153 &self.repr,
154 &other.repr,
155 Some((self.context.precision, other.context.precision)),
156 ))
157 }
158}
159
160impl<R: Round, const B: Word> Ord for FBig<R, B> {
161 #[inline]
162 fn cmp(&self, other: &Self) -> Ordering {
163 repr_cmp_same_base::<B, false>(
164 &self.repr,
165 &other.repr,
166 Some((self.context.precision, other.context.precision)),
167 )
168 }
169}
170
171impl<R: Round, const B: Word> AbsOrd for FBig<R, B> {
172 #[inline]
173 fn abs_cmp(&self, other: &Self) -> Ordering {
174 repr_cmp_same_base::<B, true>(
175 &self.repr,
176 &other.repr,
177 Some((self.context.precision, other.context.precision)),
178 )
179 }
180}
181
182pub(crate) fn repr_cmp_ubig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &UBig) -> Ordering {
183 if lhs.is_infinite() {
185 return if lhs.exponent > 0 || ABS {
186 Ordering::Greater
187 } else {
188 Ordering::Less
189 };
190 }
191
192 if !ABS && lhs.significand.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 let mut rhs: IBig = rhs.clone().into();
209 if lhs.exponent < 0 {
210 shl_digits_in_place::<B>(&mut rhs, (-lhs.exponent) as usize);
211 lhs.significand.cmp(&rhs)
212 } else {
213 shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(&rhs)
214 }
215}
216
217pub(crate) fn repr_cmp_ibig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &IBig) -> Ordering {
218 if lhs.is_infinite() {
220 return if lhs.exponent > 0 || ABS {
221 Ordering::Greater
222 } else {
223 Ordering::Less
224 };
225 }
226
227 let sign = if ABS {
229 Sign::Positive
230 } else {
231 match (lhs.significand.sign(), rhs.sign()) {
232 (Sign::Positive, Sign::Positive) => Sign::Positive,
233 (Sign::Positive, Sign::Negative) => return Ordering::Greater,
234 (Sign::Negative, Sign::Positive) => return Ordering::Less,
235 (Sign::Negative, Sign::Negative) => Sign::Negative,
236 }
237 };
238
239 let (lhs_lo, lhs_hi) = lhs.log2_bounds();
241 let (rhs_lo, rhs_hi) = rhs.log2_bounds();
242 if lhs_lo > rhs_hi {
243 return sign * Ordering::Greater;
244 }
245 if lhs_hi < rhs_lo {
246 return sign * Ordering::Less;
247 }
248
249 if lhs.exponent < 0 {
251 lhs.significand
252 .cmp(&shl_digits::<B>(rhs, (-lhs.exponent) as usize))
253 } else {
254 shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(rhs)
255 }
256}
257
258macro_rules! impl_abs_ord_with_method {
259 ($T:ty, $method:ident) => {
260 impl<const B: Word> AbsOrd<$T> for Repr<B> {
261 #[inline]
262 fn abs_cmp(&self, other: &$T) -> Ordering {
263 $method::<B, true>(self, other)
264 }
265 }
266 impl<const B: Word> AbsOrd<Repr<B>> for $T {
267 #[inline]
268 fn abs_cmp(&self, other: &Repr<B>) -> Ordering {
269 $method::<B, true>(other, self).reverse()
270 }
271 }
272 impl<R: Round, const B: Word> AbsOrd<$T> for FBig<R, B> {
273 #[inline]
274 fn abs_cmp(&self, other: &$T) -> Ordering {
275 $method::<B, true>(&self.repr, other)
276 }
277 }
278 impl<R: Round, const B: Word> AbsOrd<FBig<R, B>> for $T {
279 #[inline]
280 fn abs_cmp(&self, other: &FBig<R, B>) -> Ordering {
281 $method::<B, true>(&other.repr, self).reverse()
282 }
283 }
284 };
285}
286impl_abs_ord_with_method!(UBig, repr_cmp_ubig);
287impl_abs_ord_with_method!(IBig, repr_cmp_ibig);