1use crate::*;
12
13use stdlib::cmp::Ordering;
14use stdlib::iter;
15
16impl PartialEq for BigDecimal {
17 fn eq(&self, rhs: &BigDecimal) -> bool {
18 self.to_ref() == rhs.to_ref()
19 }
20}
21
22impl<'rhs, T> PartialEq<T> for BigDecimalRef<'_>
23where
24 T: Into<BigDecimalRef<'rhs>> + Copy,
25{
26 fn eq(&self, rhs: &T) -> bool {
27 let rhs: BigDecimalRef<'rhs> = (*rhs).into();
28 check_equality_bigdecimal_ref(*self, rhs)
29 }
30}
31
32fn check_equality_bigdecimal_ref(lhs: BigDecimalRef, rhs: BigDecimalRef) -> bool {
33 match (lhs.sign(), rhs.sign()) {
34 (Sign::NoSign, Sign::NoSign) => return true,
36 (a, b) if a != b => return false,
38 _ => {}
40 }
41
42 let unscaled_int;
43 let scaled_int;
44 let trailing_zero_count;
45 match arithmetic::checked_diff(lhs.scale, rhs.scale) {
46 (Ordering::Equal, _) => {
47 return lhs.digits == rhs.digits;
48 }
49 (Ordering::Greater, Some(scale_diff)) => {
50 unscaled_int = lhs.digits;
51 scaled_int = rhs.digits;
52 trailing_zero_count = scale_diff;
53 }
54 (Ordering::Less, Some(scale_diff)) => {
55 unscaled_int = rhs.digits;
56 scaled_int = lhs.digits;
57 trailing_zero_count = scale_diff;
58 }
59 _ => {
60 return false;
63 }
64 }
65
66 if true {
match (&trailing_zero_count, &0) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_ne!(trailing_zero_count, 0);
67
68 if highest_bit_lessthan_scaled(unscaled_int, scaled_int, trailing_zero_count) {
71 return false;
72 }
73
74 if trailing_zero_count < 20 {
76 let pow = ten_to_the_u64(trailing_zero_count as u8);
77
78 let mut a_digits = unscaled_int.iter_u32_digits();
79 let mut b_digits = scaled_int.iter_u32_digits();
80
81 let mut carry = 0;
82 loop {
83 match (a_digits.next(), b_digits.next()) {
84 (Some(next_a), Some(next_b)) => {
85 let wide_b = match (next_b as u64).checked_mul(pow) {
86 Some(tmp) => tmp + carry,
87 None => break,
88 };
89
90 let true_b = wide_b as u32;
91
92 if next_a != true_b {
93 return false;
94 }
95
96 carry = wide_b >> 32;
97 }
98 (None, Some(_)) => {
99 return false;
100 }
101 (Some(a_digit), None) => {
102 if a_digit != (carry as u32) {
103 return false;
104 }
105 carry = 0;
106 }
107 (None, None) => {
108 return carry == 0;
109 }
110 }
111 }
112
113 let scaled_int = scaled_int * pow;
115 return &scaled_int == unscaled_int;
116 }
117
118 let trailing_zero_count = trailing_zero_count.to_usize().unwrap();
119 let unscaled_digits = unscaled_int.to_radix_le(10);
120
121 if trailing_zero_count > unscaled_digits.len() {
122 return false;
123 }
124
125 let (low_digits, overlap_digits) = unscaled_digits.split_at(trailing_zero_count);
127
128 if low_digits.iter().any(|&d| d != 0) {
130 return false;
131 }
132
133 let scaled_digits = scaled_int.to_radix_le(10);
134
135 if overlap_digits.len() != scaled_digits.len() {
137 return false;
138 }
139
140 overlap_digits.iter().zip(scaled_digits.iter()).all(|(digit_a, digit_b)| digit_a == digit_b)
142}
143
144
145impl PartialOrd for BigDecimal {
146 #[inline]
147 fn partial_cmp(&self, other: &BigDecimal) -> Option<Ordering> {
148 Some(self.cmp(other))
149 }
150}
151
152impl PartialOrd for BigDecimalRef<'_> {
153 fn partial_cmp(&self, other: &BigDecimalRef<'_>) -> Option<Ordering> {
154 Some(self.cmp(other))
155 }
156}
157
158
159impl Ord for BigDecimal {
160 #[inline]
161 fn cmp(&self, other: &BigDecimal) -> Ordering {
162 self.to_ref().cmp(&other.to_ref())
163 }
164}
165
166impl Ord for BigDecimalRef<'_> {
167 #[inline]
187 fn cmp(&self, other: &BigDecimalRef) -> Ordering {
188 use Ordering::*;
189
190 let scmp = self.sign().cmp(&other.sign());
191 if scmp != Ordering::Equal {
192 return scmp;
193 }
194
195 if self.sign() == Sign::NoSign {
196 return Ordering::Equal;
197 }
198
199 let result = match arithmetic::checked_diff(self.scale, other.scale) {
200 (Greater, Some(scale_diff)) | (Equal, Some(scale_diff)) => {
201 compare_scaled_biguints(self.digits, other.digits, scale_diff)
202 }
203 (Less, Some(scale_diff)) => {
204 compare_scaled_biguints(other.digits, self.digits, scale_diff).reverse()
205 }
206 (res, None) => {
207 res.reverse()
213 }
214 };
215
216 if other.sign == Sign::Minus {
217 result.reverse()
218 } else {
219 result
220 }
221 }
222}
223
224
225fn compare_scaled_biguints(a: &BigUint, b: &BigUint, scale_diff: u64) -> Ordering {
228 use Ordering::*;
229
230 if scale_diff == 0 {
231 return a.cmp(b);
232 }
233
234 if highest_bit_lessthan_scaled(a, b, scale_diff) {
236 return Ordering::Less;
237 }
238
239 if let Some(result) = compare_scalar_biguints(a, b, scale_diff) {
241 return result;
242 }
243
244 let a_digit_count = count_decimal_digits_uint(a);
245 let b_digit_count = count_decimal_digits_uint(b);
246
247 let digit_count_cmp = a_digit_count.cmp(&(b_digit_count + scale_diff));
248 if digit_count_cmp != Equal {
249 return digit_count_cmp;
250 }
251
252 let a_digits = a.to_radix_le(10);
253 let b_digits = b.to_radix_le(10);
254
255 if true {
match (&a_digits.len(), &(a_digit_count as usize)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(a_digits.len(), a_digit_count as usize);
256 if true {
match (&b_digits.len(), &(b_digit_count as usize)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(b_digits.len(), b_digit_count as usize);
257
258 let mut a_it = a_digits.iter().rev();
259 let mut b_it = b_digits.iter().rev();
260
261 loop {
262 match (a_it.next(), b_it.next()) {
263 (Some(ai), Some(bi)) => {
264 match ai.cmp(bi) {
265 Equal => continue,
266 result => return result,
267 }
268 }
269 (Some(&ai), None) => {
270 if ai == 0 && a_it.all(Zero::is_zero) {
271 return Equal;
272 } else {
273 return Greater;
274 }
275 }
276 (None, Some(&bi)) => {
277 if bi == 0 && b_it.all(Zero::is_zero) {
278 return Equal;
279 } else {
280 return Less;
281 }
282 }
283 (None, None) => {
284 return Equal;
285 }
286 }
287 }
288}
289
290fn compare_scalar_biguints(a: &BigUint, b: &BigUint, scale_diff: u64) -> Option<Ordering> {
292 let scale_diff = scale_diff.to_usize()?;
293
294 compare_scaled_uints::<u64>(a, b, scale_diff)
296 .or_else(|| compare_scaled_uints::<u128>(a, b, scale_diff))
297}
298
299fn compare_scaled_uints<'a, T>(
301 a: &'a BigUint,
302 b: &'a BigUint,
303 scale_diff: usize,
304) -> Option<Ordering>
305where
306 T: num_traits::PrimInt + TryFrom<&'a BigUint>,
307{
308 let ten = T::from(10).unwrap();
309
310 let a = T::try_from(a).ok();
311 let b = T::try_from(b).ok().and_then(
312 |b| num_traits::checked_pow(ten, scale_diff).and_then(
313 |p| b.checked_mul(&p)));
314
315 match (a, b) {
316 (Some(a), Some(scaled_b)) => Some(a.cmp(&scaled_b)),
317 (Some(_), None) => Some(Ordering::Less),
319 (None, Some(_)) => Some(Ordering::Greater),
321 (None, None) => None,
323 }
324}
325
326fn highest_bit_lessthan_scaled(a: &BigUint, b: &BigUint, scale: u64) -> bool {
336 let a_bits = a.bits();
337 let b_bits = b.bits();
338 if a_bits < b_bits {
339 return true;
340 }
341 let log_scale = LOG2_10 * scale as f64;
342 match b_bits.checked_add(log_scale as u64) {
343 Some(scaled_b_bit) => a_bits < scaled_b_bit,
344 None => true, }
346}
347
348#[cfg(test)]
349mod test {
350 use super::*;
351
352 mod compare_scaled_biguints {
353 use super::*;
354
355 macro_rules! impl_test {
356 ($name:ident: $a:literal > $b:literal e $e:literal) => {
357 impl_test!($name: $a Greater $b e $e);
358 };
359 ($name:ident: $a:literal < $b:literal e $e:literal) => {
360 impl_test!($name: $a Less $b e $e);
361 };
362 ($name:ident: $a:literal = $b:literal e $e:literal) => {
363 impl_test!($name: $a Equal $b e $e);
364 };
365 ($name:ident: $a:literal $op:ident $b:literal e $e:literal) => {
366 #[test]
367 fn $name() {
368 let a: BigUint = $a.parse().unwrap();
369 let b: BigUint = $b.parse().unwrap();
370
371 let result = compare_scaled_biguints(&a, &b, $e);
372 assert_eq!(result, Ordering::$op);
373 }
374 };
375 }
376
377 impl_test!(case_500_51e1: "500" < "51" e 1);
378 impl_test!(case_500_44e1: "500" > "44" e 1);
379 impl_test!(case_5000_50e2: "5000" = "50" e 2);
380 impl_test!(case_1234e9_12345e9: "1234000000000" < "12345" e 9);
381 impl_test!(case_1116xx459_759xx717e2: "1116386634271380982470843247639640260491505327092723527088459" < "759522625769651746138617259189939751893902453291243506584717" e 2);
382 }
383
384 #[test]
386 fn test_cmp_on_exp_boundaries() {
387 let a = BigDecimal::new(1.into(), i64::MAX);
388 let z = BigDecimal::new(1.into(), i64::MIN);
389 assert_ne!(a, z);
390 assert_ne!(z, a);
391
392 assert!(a < z);
393
394 assert_eq!(a, a);
395 assert_eq!(z, z);
396 }
397
398 mod ord {
399 use super::*;
400
401 macro_rules! impl_test {
402 ($name:ident: $a:literal < $b:literal) => {
403 #[test]
404 fn $name() {
405 let a: BigDecimal = $a.parse().unwrap();
406 let b: BigDecimal = $b.parse().unwrap();
407
408 assert!(&a < &b);
409 assert!(&b > &a);
410 assert_ne!(a, b);
411 }
412 };
413 }
414
415 impl_test!(case_diff_signs: "-1" < "1");
416 impl_test!(case_n1_0: "-1" < "0");
417 impl_test!(case_0_1: "0" < "1");
418 impl_test!(case_1d2345_1d2346: "1.2345" < "1.2346");
419 impl_test!(case_compare_extreme: "1e-9223372036854775807" < "1");
420 impl_test!(case_compare_extremes: "1e-9223372036854775807" < "1e9223372036854775807");
421 impl_test!(case_small_difference: "472697816888807260.1604" < "472697816888807260.16040000000000000000001");
422 impl_test!(case_very_small_diff: "-1.0000000000000000000000000000000000000000000000000001" < "-1");
423
424 impl_test!(case_1_2p128: "1" < "340282366920938463463374607431768211455");
425 impl_test!(case_1_1e39: "1000000000000000000000000000000000000000" < "1e41");
426
427 impl_test!(case_1d414xxx573: "1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000" < "1.41421356237309504880168872420969807856967187537694807317667974000000000");
428 impl_test!(case_11d414xxx573: "1.414213562373095048801688724209698078569671875376948073176679730000000000000000000000000000000000000" < "11.41421356237309504880168872420969807856967187537694807317667974000000000");
429 }
430
431 mod eq {
432 use super::*;
433
434 macro_rules! impl_test {
435 ($name:ident: $a:literal = $b:literal) => {
436 #[test]
437 fn $name() {
438 let a: BigDecimal = $a.parse().unwrap();
439 let b: BigDecimal = $b.parse().unwrap();
440
441 assert_eq!(&a, &b);
442 assert_eq!(a, b);
443 }
444 };
445 }
446
447 impl_test!(case_zero: "0" = "0.00");
448 impl_test!(case_1_1d00: "1" = "1.00");
449 impl_test!(case_n1_n1000en3: "-1" = "-1000e-3");
450 impl_test!(case_0d000034500_345en7: "0.000034500" = "345e-7");
451 }
452
453 #[test]
454 fn test_borrow_neg_cmp() {
455 let x: BigDecimal = "1514932018891593.916341142773".parse().unwrap();
456 let y: BigDecimal = "1514932018891593916341142773e-12".parse().unwrap();
457
458 assert_eq!(x, y);
459
460 let x_ref = x.to_ref();
461 assert_eq!(x_ref, &y);
462 assert_ne!(x_ref.neg(), x_ref);
463 assert_eq!(x_ref.neg().neg(), x_ref);
464 }
465
466 #[cfg(property_tests)]
467 mod prop {
468 use super::*;
469 use proptest::prelude::*;
470
471 proptest! {
472 #![proptest_config(ProptestConfig { cases: 5000, ..Default::default() })]
473
474 #[test]
475 fn cmp_matches_f64(
476 f in proptest::num::f64::NORMAL | proptest::num::f64::SUBNORMAL | proptest::num::f64::ZERO,
477 g in proptest::num::f64::NORMAL | proptest::num::f64::SUBNORMAL | proptest::num::f64::ZERO
478 ) {
479 let a: BigDecimal = BigDecimal::from_f64(f).unwrap();
480 let b: BigDecimal = BigDecimal::from_f64(g).unwrap();
481
482 let expected = PartialOrd::partial_cmp(&f, &g).unwrap();
483 let value = a.cmp(&b);
484
485 prop_assert_eq!(expected, value)
486 }
487 }
488 }
489}