dashu_int/third_party/
num_order.rs1use crate::{ibig::IBig, ubig::UBig};
4use core::{cmp::Ordering, hash::Hash};
5use dashu_base::{BitTest, FloatEncoding, Sign, Signed};
6use num_order::{NumHash, NumOrd};
7
8impl NumHash for UBig {
9 fn num_hash<H: core::hash::Hasher>(&self, state: &mut H) {
10 let m = self % (i128::MAX as u128);
11 (m as i128).hash(state)
12 }
13}
14impl NumHash for IBig {
15 fn num_hash<H: core::hash::Hasher>(&self, state: &mut H) {
16 (self % i128::MAX).hash(state)
17 }
18}
19
20impl NumOrd<UBig> for UBig {
21 #[inline]
22 fn num_cmp(&self, other: &UBig) -> Ordering {
23 self.cmp(other)
24 }
25 #[inline]
26 fn num_partial_cmp(&self, other: &UBig) -> Option<Ordering> {
27 self.partial_cmp(other)
28 }
29}
30
31impl NumOrd<IBig> for UBig {
32 #[inline]
33 fn num_cmp(&self, other: &IBig) -> Ordering {
34 let (rhs_sign, rhs_mag) = other.as_sign_repr();
35 match rhs_sign {
36 Sign::Positive => self.repr().cmp(&rhs_mag),
37 Sign::Negative => Ordering::Greater,
38 }
39 }
40 #[inline]
41 fn num_partial_cmp(&self, other: &IBig) -> Option<Ordering> {
42 Some(self.num_cmp(other))
43 }
44}
45
46impl NumOrd<UBig> for IBig {
47 #[inline]
48 fn num_cmp(&self, other: &UBig) -> Ordering {
49 let (lhs_sign, lhs_mag) = self.as_sign_repr();
50 match lhs_sign {
51 Sign::Positive => lhs_mag.cmp(&other.repr()),
52 Sign::Negative => Ordering::Less,
53 }
54 }
55 #[inline]
56 fn num_partial_cmp(&self, other: &UBig) -> Option<Ordering> {
57 Some(self.num_cmp(other))
58 }
59}
60
61impl NumOrd<IBig> for IBig {
62 #[inline]
63 fn num_cmp(&self, other: &IBig) -> Ordering {
64 self.cmp(other)
65 }
66 #[inline]
67 fn num_partial_cmp(&self, other: &IBig) -> Option<Ordering> {
68 self.partial_cmp(other)
69 }
70}
71
72macro_rules! impl_num_ord_ubig_with_unsigned {
73 ($($t:ty)*) => {$(
74 impl NumOrd<$t> for UBig {
75 #[inline]
76 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
77 self.partial_cmp(&UBig::from_unsigned(*other))
78 }
79 }
80 impl NumOrd<UBig> for $t {
81 #[inline]
82 fn num_partial_cmp(&self, other: &UBig) -> Option<Ordering> {
83 UBig::from_unsigned(*self).partial_cmp(other)
84 }
85 }
86 )*};
87}
88impl_num_ord_ubig_with_unsigned!(u8 u16 u32 u64 u128 usize);
89
90macro_rules! impl_num_ord_ubig_with_signed {
91 ($($t:ty)*) => {$(
92 impl NumOrd<$t> for UBig {
93 #[inline]
94 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
95 self.num_partial_cmp(&IBig::from_signed(*other))
96 }
97 }
98 impl NumOrd<UBig> for $t {
99 #[inline]
100 fn num_partial_cmp(&self, other: &UBig) -> Option<Ordering> {
101 IBig::from_signed(*self).num_partial_cmp(other)
102 }
103 }
104 )*};
105}
106impl_num_ord_ubig_with_signed!(i8 i16 i32 i64 i128 isize);
107
108macro_rules! impl_num_ord_ibig_with_unsigned {
109 ($($t:ty)*) => {$(
110 impl NumOrd<$t> for IBig {
111 #[inline]
112 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
113 self.partial_cmp(&IBig::from_unsigned(*other))
114 }
115 }
116 impl NumOrd<IBig> for $t {
117 #[inline]
118 fn num_partial_cmp(&self, other: &IBig) -> Option<Ordering> {
119 IBig::from_unsigned(*self).partial_cmp(other)
120 }
121 }
122 )*};
123}
124impl_num_ord_ibig_with_unsigned!(u8 u16 u32 u64 u128 usize);
125
126macro_rules! impl_num_ord_ibig_with_signed {
127 ($($t:ty)*) => {$(
128 impl NumOrd<$t> for IBig {
129 #[inline]
130 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
131 self.partial_cmp(&IBig::from_signed(*other))
132 }
133 }
134 impl NumOrd<IBig> for $t {
135 #[inline]
136 fn num_partial_cmp(&self, other: &IBig) -> Option<Ordering> {
137 IBig::from_signed(*self).partial_cmp(other)
138 }
139 }
140 )*};
141}
142impl_num_ord_ibig_with_signed!(i8 i16 i32 i64 i128 isize);
143
144macro_rules! impl_num_ord_ubig_with_float {
145 ($($t:ty)*) => {$(
146 impl NumOrd<$t> for UBig {
147 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
148 if other.is_nan() {
150 return None;
151 } else if *other == 0. {
152 return match self.is_zero() {
153 true => Some(Ordering::Equal),
154 false => Some(Ordering::Greater)
155 };
156 }
157
158 if other.sign() == Sign::Negative {
160 return Some(Ordering::Greater);
161 }
162
163 if other.is_infinite() {
165 return Some(Ordering::Less);
166 }
167
168 let self_bits = self.bit_len();
170 if self_bits > (<$t>::MANTISSA_DIGITS as usize + <$t>::MAX_EXP as usize) {
171 return Some(Ordering::Greater);
172 }
173
174 let (man, exp) = other.decode().unwrap();
176 let other_bits = man.bit_len() as isize + exp as isize;
177 if other_bits < 0 {
178 return Some(Ordering::Greater);
179 } else if self_bits > other_bits as usize {
180 return Some(Ordering::Greater);
181 } else if self_bits < other_bits as usize {
182 return Some(Ordering::Less);
183 }
184
185 if exp >= 0 {
187 let shifted = UBig::from(man.unsigned_abs()) << exp as usize;
188 self.partial_cmp(&shifted)
189 } else {
190 (self << (-exp as usize)).partial_cmp(&UBig::from(man.unsigned_abs()))
191 }
192 }
193 }
194
195 impl NumOrd<UBig> for $t {
196 #[inline]
197 fn num_partial_cmp(&self, other: &UBig) -> Option<Ordering> {
198 other.num_partial_cmp(self).map(|ord| ord.reverse())
199 }
200 }
201 )*};
202}
203impl_num_ord_ubig_with_float!(f32 f64);
204
205macro_rules! impl_num_ord_ibig_with_float {
206 ($($t:ty)*) => {$(
207 impl NumOrd<$t> for IBig {
208 fn num_partial_cmp(&self, other: &$t) -> Option<Ordering> {
209 if other.is_nan() {
211 return None;
212 } else if *other == 0. {
213 return match self.is_zero() {
214 true => Some(Ordering::Equal),
215 false => Some(self.sign() * Ordering::Greater)
216 };
217 }
218
219 let sign = match (self.sign(), other.sign()) {
221 (Sign::Positive, Sign::Positive) => Sign::Positive,
222 (Sign::Positive, Sign::Negative) => return Some(Ordering::Greater),
223 (Sign::Negative, Sign::Positive) => return Some(Ordering::Less),
224 (Sign::Negative, Sign::Negative) => Sign::Negative,
225 };
226
227 if other.is_infinite() {
229 return Some(-sign * Ordering::Less);
230 }
231
232 let self_bits = self.bit_len();
234 if self_bits > (<$t>::MANTISSA_DIGITS as usize + <$t>::MAX_EXP as usize) {
235 return Some(sign * Ordering::Greater);
236 }
237
238 let (man, exp) = other.decode().unwrap();
240 let other_bits = man.bit_len() as isize + exp as isize; if other_bits < 0 {
242 return Some(sign * Ordering::Greater);
243 } else if self_bits > other_bits as usize {
244 return Some(sign * Ordering::Greater);
245 } else if self_bits < other_bits as usize {
246 return Some(sign * Ordering::Less);
247 }
248
249 if exp >= 0 {
251 let shifted = IBig::from(man) << exp as usize;
252 self.partial_cmp(&shifted)
253 } else {
254 (self << (-exp as usize)).partial_cmp(&IBig::from(man))
255 }
256 }
257 }
258
259 impl NumOrd<IBig> for $t {
260 #[inline]
261 fn num_partial_cmp(&self, other: &IBig) -> Option<Ordering> {
262 other.num_partial_cmp(self).map(|ord| ord.reverse())
263 }
264 }
265 )*};
266}
267impl_num_ord_ibig_with_float!(f32 f64);