1use crate::*;
5use rounding::{NonDigitRoundingData, InsigData};
6use stdlib::fmt::Write;
7use stdlib::num::NonZeroUsize;
8
9
10include!(concat!(env!("OUT_DIR"), "/exponential_format_threshold.rs"));
14
15
16impl fmt::Display for BigDecimal {
17 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18 dynamically_format_decimal(
19 self.to_ref(),
20 f,
21 EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD,
22 EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD,
23 )
24 }
25}
26
27impl fmt::Display for BigDecimalRef<'_> {
28 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29 dynamically_format_decimal(
30 *self,
31 f,
32 EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD,
33 EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD,
34 )
35 }
36}
37
38
39impl fmt::LowerExp for BigDecimal {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 fmt::LowerExp::fmt(&self.to_ref(), f)
42 }
43}
44
45impl fmt::LowerExp for BigDecimalRef<'_> {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 let (abs_int, scale) = get_abs_int_scale(*self);
48 format_exponential(f, abs_int, self.sign, scale, "e")
49 }
50}
51
52
53impl fmt::UpperExp for BigDecimal {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 fmt::UpperExp::fmt(&self.to_ref(), f)
56 }
57}
58
59impl fmt::UpperExp for BigDecimalRef<'_> {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 let (abs_int, scale) = get_abs_int_scale(*self);
62 format_exponential(f, abs_int, self.sign, scale, "E")
63 }
64}
65
66
67impl fmt::Debug for BigDecimal {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 if f.alternate() {
70 f.write_fmt(format_args!("BigDecimal(\"{0}e{1}\")", self.int_val,
-self.scale))write!(f, "BigDecimal(\"{}e{:}\")", self.int_val, -self.scale)
71 } else {
72 f.write_fmt(format_args!("BigDecimal(sign={0:?}, scale={1}, digits={2:?})",
self.sign(), self.scale, self.int_val.magnitude().to_u64_digits()))write!(f,
73 "BigDecimal(sign={:?}, scale={}, digits={:?})",
74 self.sign(), self.scale, self.int_val.magnitude().to_u64_digits()
75 )
76 }
77 }
78}
79
80fn get_abs_int_scale(this: BigDecimalRef) -> (String, i64) {
81 let abs_int = this.digits.to_str_radix(10);
83 let scale = if this.is_zero() { 0 } else { this.scale };
85
86 (abs_int, scale)
87}
88
89
90fn dynamically_format_decimal(
91 this: BigDecimalRef,
92 f: &mut fmt::Formatter,
93 leading_zero_threshold: usize,
94 trailing_zero_threshold: usize,
95) -> fmt::Result {
96 let (abs_int, scale) = get_abs_int_scale(this);
97
98 let leading_zero_count = scale
100 .to_u64()
101 .and_then(|scale| scale.checked_sub(abs_int.len() as u64))
102 .unwrap_or(0);
103
104 let trailing_zero_count = scale
106 .checked_neg()
107 .and_then(|d| d.to_u64());
108
109 let trailing_zeros = f.precision().map(|_| 0)
111 .or(trailing_zero_count)
112 .unwrap_or(0);
113
114 let leading_zero_threshold = leading_zero_threshold as u64;
115 let trailing_zero_threshold = trailing_zero_threshold as u64;
116
117 if f.precision().is_none() && leading_zero_threshold < leading_zero_count {
121 format_exponential(f, abs_int, this.sign, scale, "E")
122 } else if trailing_zero_threshold < trailing_zeros {
123 format_dotless_exponential(f, abs_int, this.sign, scale, "e")
125 } else {
126 format_full_scale(f, abs_int, this.sign, scale)
127 }
128}
129
130
131pub(crate) struct FullScaleFormatter<'a>(pub BigDecimalRef<'a>);
132
133impl fmt::Display for FullScaleFormatter<'_> {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 let n = self.0;
136 let non_negative = #[allow(non_exhaustive_omitted_patterns)] match n.sign {
Sign::Plus | Sign::NoSign => true,
_ => false,
}matches!(n.sign, Sign::Plus | Sign::NoSign);
137
138 let mut digits = n.digits.to_string();
139
140 if n.scale <= 0 {
141 digits.extend(stdlib::iter::repeat('0').take(n.scale.neg() as usize));
142 } else if n.scale < digits.len() as i64 {
143 digits.insert(digits.len() - n.scale as usize, '.');
144 } else {
145 let mut digit_vec = digits.into_bytes();
146
147 let dest_str_size = n.scale as usize + 2;
148 let digit_count = digit_vec.len();
149 let leading_char_idx = dest_str_size - digit_count;
150
151 digit_vec.resize(dest_str_size, b'0');
152 digit_vec.copy_within(0..digit_count, leading_char_idx);
153 fill_slice(&mut digit_vec[..digit_count.min(leading_char_idx)], b'0');
154
155 digit_vec[1] = b'.';
156 digits = String::from_utf8(digit_vec).unwrap();
157 }
158
159 f.pad_integral(non_negative, "", &digits)
160 }
161}
162
163
164fn format_full_scale(
165 f: &mut fmt::Formatter,
166 abs_int: String,
167 sign: Sign,
168 scale: i64,
169) -> fmt::Result {
170 use stdlib::cmp::Ordering::*;
171
172 let mut digits = abs_int.into_bytes();
173 let mut exp = 0;
174 let non_negative = #[allow(non_exhaustive_omitted_patterns)] match sign {
Sign::Plus | Sign::NoSign => true,
_ => false,
}matches!(sign, Sign::Plus | Sign::NoSign);
175
176 if true {
match (&digits.len(), &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!(digits.len(), 0);
177
178 let rounder = NonDigitRoundingData::default_with_sign(sign);
179
180 if scale <= 0 {
181 exp = (scale as i128).neg();
182 zero_right_pad_integer_ascii_digits(&mut digits, &mut exp, f.precision());
184 } else {
185 let scale = scale as u64;
186
187 let target_scale = f.precision().and_then(|prec| prec.to_u64()).unwrap_or(scale);
192
193 if scale < digits.len() as u64 {
194 format_ascii_digits_with_integer_and_fraction(&mut digits, scale, target_scale, rounder);
196 } else {
197 format_ascii_digits_no_integer(&mut digits, scale, target_scale, rounder);
199 }
200 }
201
202 let mut buf = String::from_utf8(digits).unwrap();
204
205 if exp != 0 {
207 buf.write_fmt(format_args!("e{0:+}", exp))write!(buf, "e{:+}", exp)?;
208 }
209
210 f.pad_integral(non_negative, "", &buf)
212}
213
214fn zero_right_pad_integer_ascii_digits(
219 digits: &mut Vec<u8>,
220 exp: &mut i128,
221 target_scale: Option<usize>,
223) {
224 if true {
if !(*exp >= 0) {
::core::panicking::panic("assertion failed: *exp >= 0")
};
};debug_assert!(*exp >= 0);
225 if true {
match (&digits.len(), &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!(digits.len(), 0);
226
227 let integer_zero_count = match exp.to_usize() {
228 Some(n) => n,
229 None => { return; }
230 };
231
232 if target_scale.is_none() && integer_zero_count > 20 {
235 return;
237 }
238
239 let fraction_zero_char_count;
240 let decimal_place_idx;
241
242 if let Some(frac_zero_count) = target_scale.and_then(NonZeroUsize::new) {
243 fraction_zero_char_count = frac_zero_count.get() + 1;
245 decimal_place_idx = Some(digits.len() + integer_zero_count);
247 } else {
248 fraction_zero_char_count = 0;
249 decimal_place_idx = None;
250 }
251
252 let total_additional_zeros = integer_zero_count.saturating_add(fraction_zero_char_count);
253
254 if total_additional_zeros > FMT_MAX_INTEGER_PADDING {
256 return;
257 }
258
259 digits.resize(digits.len() + total_additional_zeros, b'0');
260 if let Some(decimal_place_idx) = decimal_place_idx {
261 digits[decimal_place_idx] = b'.';
262 }
263
264 *exp = 0;
266}
267
268
269fn format_ascii_digits_with_integer_and_fraction(
274 digits_ascii_be: &mut Vec<u8>,
275 scale: u64,
276 target_scale: u64,
277 rounder: NonDigitRoundingData,
278) {
279 if true {
if !(scale < digits_ascii_be.len() as u64) {
{ ::std::rt::begin_panic("No integer digits"); }
};
};debug_assert!(scale < digits_ascii_be.len() as u64, "No integer digits");
280 let mut digit_scale = scale;
281
282 if target_scale < scale {
284 let digit_count_to_remove = (scale - target_scale)
285 .to_usize()
286 .expect("Precision exceeds maximum usize");
287
288 let rounding_idx = NonZeroUsize::new(digits_ascii_be.len() - digit_count_to_remove)
289 .expect("decimal must have integer digits");
290
291 let scale_diff = round_ascii_digits(digits_ascii_be, rounding_idx, rounder);
293
294 match scale_diff.checked_sub(digit_scale as usize) {
295 None | Some(0) => {
296 digit_scale -= scale_diff as u64;
297 }
298 Some(zeros_to_add) => {
299 digits_ascii_be.resize(digits_ascii_be.len() + zeros_to_add, b'0');
300 digit_scale = 0;
301 }
302 }
303 }
304
305 if target_scale != 0 {
307 let integer_digit_count = (digits_ascii_be.len() as u64 - digit_scale)
309 .to_usize()
310 .expect("Number of digits exceeds maximum usize");
311
312 digits_ascii_be.insert(integer_digit_count, b'.');
313 }
314
315 if digit_scale < target_scale {
316 let trailing_zero_count = (target_scale - digit_scale)
317 .to_usize()
318 .expect("Too Big");
319
320 digits_ascii_be.resize(digits_ascii_be.len() + trailing_zero_count, b'0');
322 digit_scale += trailing_zero_count as u64;
323 }
324
325 if true {
match (&digit_scale, &target_scale) {
(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!(digit_scale, target_scale);
326}
327
328
329fn format_ascii_digits_no_integer(
334 digits_ascii_be: &mut Vec<u8>,
335 scale: u64,
336 target_scale: u64,
337 rounder: NonDigitRoundingData,
338) {
339 use stdlib::cmp::Ordering::*;
340
341 if true {
if !(scale >= digits_ascii_be.len() as u64) {
::core::panicking::panic("assertion failed: scale >= digits_ascii_be.len() as u64")
};
};debug_assert!(scale >= digits_ascii_be.len() as u64);
342 let leading_zeros = scale - digits_ascii_be.len() as u64;
343
344 match arithmetic::diff(target_scale, leading_zeros) {
345 (Less, intermediate_zeros) | (Equal, intermediate_zeros) => {
347 let (insig_digit, trailing_digits) = if intermediate_zeros > 0 {
349 (0, digits_ascii_be.as_slice())
350 } else {
351 (digits_ascii_be[0] - b'0', &digits_ascii_be[1..])
352 };
353
354 let insig_data = InsigData::from_digit_and_lazy_trailing_zeros(
355 rounder, insig_digit, || trailing_digits.iter().all(|&d| d == b'0')
356 );
357
358 let rounded_digit = insig_data.round_digit(0);
359 if true {
match (&rounded_digit, &10) {
(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!(rounded_digit, 10);
360
361 digits_ascii_be.clear();
362
363 if target_scale > 0 {
364 digits_ascii_be.resize(target_scale as usize + 1, b'0');
365 }
366
367 digits_ascii_be.push(rounded_digit + b'0');
368
369 if target_scale > 0 {
370 digits_ascii_be[1] = b'.';
371 }
372 }
373 (Greater, sig_digit_count) => {
374 let significant_digit_count = sig_digit_count
375 .to_usize()
376 .and_then(NonZeroUsize::new)
377 .expect("Request overflow in sig_digit_count");
378
379 let mut digit_scale = scale;
380
381 if significant_digit_count.get() < digits_ascii_be.len() {
383 let removed_digit_count = round_ascii_digits(
384 digits_ascii_be, significant_digit_count, rounder
385 );
386
387 digit_scale -= removed_digit_count as u64;
388 }
389
390 let trailing_zeros = target_scale - digit_scale;
392
393 let dest_len = target_scale as usize + 2;
395
396 let sig_digit_count = digits_ascii_be.len();
398
399 let sig_digit_idx = dest_len - trailing_zeros as usize - sig_digit_count;
401
402 digits_ascii_be.resize(dest_len, b'0');
404
405 if digit_scale != 0 {
407 digits_ascii_be.copy_within(..sig_digit_count, sig_digit_idx);
409
410 fill_slice(&mut digits_ascii_be[..sig_digit_count.min(sig_digit_idx)], b'0');
412 } else {
413 if true {
match (&sig_digit_count, &1) {
(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!(sig_digit_count, 1);
414 }
415
416 digits_ascii_be[1] = b'.';
418 }
419 }
420}
421
422#[cfg(rust_1_50)]
423fn fill_slice<T: Clone>(v: &mut [T], value: T) {
424 v.fill(value);
425}
426
427#[cfg(not(rust_1_50))]
428fn fill_slice<T: Clone>(v: &mut [T], value: T) {
429 for i in v.iter_mut() {
430 *i = value.clone();
431 }
432}
433
434
435fn format_dotless_exponential(
440 f: &mut fmt::Formatter,
441 mut abs_int: String,
442 sign: Sign,
443 scale: i64,
444 e_symbol: &str,
445) -> fmt::Result {
446 if true {
if !(scale <= 0) {
::core::panicking::panic("assertion failed: scale <= 0")
};
};debug_assert!(scale <= 0);
447
448 abs_int.write_fmt(format_args!("{0}{1:+}", e_symbol, -scale))write!(abs_int, "{}{:+}", e_symbol, -scale).unwrap();
449 let non_negative = #[allow(non_exhaustive_omitted_patterns)] match sign {
Sign::Plus | Sign::NoSign => true,
_ => false,
}matches!(sign, Sign::Plus | Sign::NoSign);
450 f.pad_integral(non_negative, "", &abs_int)
451}
452
453fn format_exponential(
454 f: &mut fmt::Formatter,
455 abs_int: String,
456 sign: Sign,
457 scale: i64,
458 e_symbol: &str,
459) -> fmt::Result {
460 let exp = (scale as i128).neg();
467 let digits = abs_int.into_bytes();
468
469 format_exponential_bigendian_ascii_digits(
470 digits, sign, exp, f, e_symbol
471 )
472}
473
474
475fn format_exponential_bigendian_ascii_digits(
476 mut digits: Vec<u8>,
477 sign: Sign,
478 mut exp: i128,
479 f: &mut fmt::Formatter,
480 e_symbol: &str,
481) -> fmt::Result {
482 let mut extra_trailing_zero_count = 0;
484
485 if let Some(prec) = f.precision() {
486 let total_prec = prec + 1;
488
489 if total_prec < digits.len() {
490 let rounder = NonDigitRoundingData::default_with_sign(sign);
492 let target_scale = NonZeroUsize::new(total_prec).unwrap();
493 let delta_exp = round_ascii_digits(&mut digits, target_scale, rounder);
494 exp += delta_exp as i128;
495 }
496
497 extra_trailing_zero_count = total_prec - digits.len();
498 }
499
500 let needs_decimal_point = digits.len() > 1 || extra_trailing_zero_count > 0;
501
502 let mut abs_int = String::from_utf8(digits).unwrap();
503
504 let exponent = abs_int.len() as i128 + exp - 1;
546
547 if needs_decimal_point {
548 abs_int.insert(1, '.');
550 }
551
552 if extra_trailing_zero_count > 0 {
553 abs_int.extend(stdlib::iter::repeat('0').take(extra_trailing_zero_count));
554 }
555
556 abs_int.write_fmt(format_args!("{0}{1:+}", e_symbol, exponent))write!(abs_int, "{}{:+}", e_symbol, exponent)?;
558
559 let non_negative = #[allow(non_exhaustive_omitted_patterns)] match sign {
Sign::Plus | Sign::NoSign => true,
_ => false,
}matches!(sign, Sign::Plus | Sign::NoSign);
560 f.pad_integral(non_negative, "", &abs_int)
562}
563
564
565fn round_ascii_digits(
573 digits_ascii_be: &mut Vec<u8>,
575 significant_digit_count: NonZeroUsize,
577 rounder: NonDigitRoundingData,
579) -> usize {
580 if true {
if !(significant_digit_count.get() < digits_ascii_be.len()) {
::core::panicking::panic("assertion failed: significant_digit_count.get() < digits_ascii_be.len()")
};
};debug_assert!(significant_digit_count.get() < digits_ascii_be.len());
581
582 let (sig_digits, insig_digits) = digits_ascii_be.split_at(significant_digit_count.get());
583 let (&insig_digit, trailing_digits) = insig_digits.split_first().unwrap_or((&b'0', &[]));
584
585 let insig_data = InsigData::from_digit_and_lazy_trailing_zeros(
586 rounder, insig_digit - b'0', || trailing_digits.iter().all(|&d| d == b'0')
587 );
588
589 let rounding_digit_pos = significant_digit_count.get() - 1;
590 let sig_digit = sig_digits[rounding_digit_pos] - b'0';
591 let rounded_digit = insig_data.round_digit(sig_digit);
592
593 let mut removed_digit_count = insig_digits.len();
595
596 digits_ascii_be.truncate(rounding_digit_pos);
598
599 if rounded_digit < 10 {
600 digits_ascii_be.push(rounded_digit + b'0');
602 return removed_digit_count;
603 }
604
605 if true {
if !(rounded_digit == 10) {
::core::panicking::panic("assertion failed: rounded_digit == 10")
};
};debug_assert!(rounded_digit == 10);
607
608 let next_non_nine_rev_pos = digits_ascii_be.iter().rev().position(|&d| d != b'9');
610 match next_non_nine_rev_pos {
611 Some(backwards_nine_count) => {
613 let digits_to_trim = backwards_nine_count + 1;
614 let idx = digits_ascii_be.len() - digits_to_trim;
615 digits_ascii_be[idx] += 1;
617 digits_ascii_be.truncate(idx + 1);
619 removed_digit_count += digits_to_trim;
621 }
622 None => {
624 digits_ascii_be.clear();
625 digits_ascii_be.push(b'1');
626 removed_digit_count += significant_digit_count.get();
628 }
629 }
630
631 return removed_digit_count;
633}
634
635
636#[inline(never)]
637pub(crate) fn write_scientific_notation<W: Write>(n: &BigDecimal, w: &mut W) -> fmt::Result {
638 if n.is_zero() {
639 return w.write_str("0e0");
640 }
641
642 if n.int_val.sign() == Sign::Minus {
643 w.write_str("-")?;
644 }
645
646 let digits = n.int_val.magnitude();
647
648 let dec_str = digits.to_str_radix(10);
649 let (first_digit, remaining_digits) = dec_str.as_str().split_at(1);
650 w.write_str(first_digit)?;
651 if !remaining_digits.is_empty() {
652 w.write_str(".")?;
653 w.write_str(remaining_digits)?;
654 }
655 w.write_fmt(format_args!("e{0}",
remaining_digits.len() as i128 - n.scale as i128))write!(w, "e{}", remaining_digits.len() as i128 - n.scale as i128)
656}
657
658
659#[inline(never)]
660pub(crate) fn write_engineering_notation<W: Write>(n: &BigDecimal, out: &mut W) -> fmt::Result {
661 if n.is_zero() {
662 return out.write_str("0e0");
663 }
664
665 if n.int_val.sign() == Sign::Minus {
666 out.write_char('-')?;
667 }
668
669 let digits = n.int_val.magnitude();
670
671 let dec_str = digits.to_str_radix(10);
672 let digit_count = dec_str.len();
673
674 let top_digit_exponent = digit_count as i128 - n.scale as i128;
675
676 let shift_amount = match top_digit_exponent.rem_euclid(3) {
677 0 => 3,
678 i => i as usize,
679 };
680
681 let exp = top_digit_exponent - shift_amount as i128;
682
683 if let Some(padding_zero_count) = shift_amount.checked_sub(dec_str.len()) {
685 let zeros = &"000"[..padding_zero_count];
686 out.write_str(&dec_str)?;
687 out.write_str(zeros)?;
688 return out.write_fmt(format_args!("e{0}", exp))write!(out, "e{}", exp);
689 }
690
691 let (head, rest) = dec_str.split_at(shift_amount);
692 if true {
match (&(exp % 3), &0) {
(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!(exp % 3, 0);
693
694 out.write_str(head)?;
695
696 if !rest.is_empty() {
697 out.write_char('.')?;
698 out.write_str(rest)?;
699 }
700
701 return out.write_fmt(format_args!("e{0}", exp))write!(out, "e{}", exp);
702}
703
704
705#[cfg(test)]
706#[allow(non_snake_case)]
707mod test {
708 use super::*;
709 use paste::*;
710
711 #[cfg(test)]
714 macro_rules! impl_case {
715 ($name:ident : $in:literal => $ex:literal) => {
716 #[test]
717 fn $name() {
718 let n: BigDecimal = $in.parse().unwrap();
719 let s = test_fmt_function!(n);
720 assert_eq!(&s, $ex);
721 }
722 };
723 }
724
725 struct Fmt<F>(F)
731 where
732 F: Fn(&mut fmt::Formatter) -> fmt::Result;
733
734 impl<F> fmt::Display for Fmt<F>
735 where
736 F: Fn(&mut fmt::Formatter) -> fmt::Result,
737 {
738 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
739 (self.0)(f)
741 }
742 }
743
744 impl<F> fmt::Debug for Fmt<F>
745 where
746 F: Fn(&mut fmt::Formatter) -> fmt::Result,
747 {
748 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
749 (self.0)(f)
750 }
751 }
752
753 mod dynamic_fmt {
754 use super::*;
755
756 macro_rules! test_fmt_function {
757 ($n:ident) => {{
758 format!("{}", Fmt(|f| dynamically_format_decimal($n.to_ref(), f, 2, 9)))
759 }};
760 }
761
762 impl_case!(case_0d123: "0.123" => "0.123");
763 impl_case!(case_0d0123: "0.0123" => "0.0123");
764 impl_case!(case_0d00123: "0.00123" => "0.00123");
765 impl_case!(case_0d000123: "0.000123" => "1.23E-4");
766
767 impl_case!(case_123d: "123." => "123");
768 impl_case!(case_123de1: "123.e1" => "1230");
769 }
770
771 mod fmt_options {
772 use super::*;
773
774 macro_rules! impl_case {
775 ($name:ident: $fmt:literal => $expected:literal) => {
776 #[test]
777 fn $name() {
778 let x = test_input();
779 let y = format!($fmt, x);
780 assert_eq!(y, $expected);
781 }
782 };
783 }
784
785 mod dec_1 {
786 use super::*;
787
788 fn test_input() -> BigDecimal {
789 "1".parse().unwrap()
790 }
791
792 impl_case!(fmt_default: "{}" => "1");
793 impl_case!(fmt_d1: "{:.1}" => "1.0");
794 impl_case!(fmt_d4: "{:.4}" => "1.0000");
795 impl_case!(fmt_4d1: "{:4.1}" => " 1.0");
796 impl_case!(fmt_r4d1: "{:>4.1}" => " 1.0");
797 impl_case!(fmt_l4d1: "{:<4.1}" => "1.0 ");
798 impl_case!(fmt_p05d1: "{:+05.1}" => "+01.0");
799
800 impl_case!(fmt_e: "{:e}" => "1e+0");
801 impl_case!(fmt_E: "{:E}" => "1E+0");
802 }
803
804 mod dec_1e1 {
805 use super::*;
806
807 fn test_input() -> BigDecimal {
808 BigDecimal::new(1.into(), -1)
809 }
810
811 impl_case!(fmt_default: "{}" => "10");
812 impl_case!(fmt_debug: "{:?}" => "BigDecimal(sign=Plus, scale=-1, digits=[1])");
813 impl_case!(fmt_debug_alt: "{:#?}" => "BigDecimal(\"1e1\")");
814 impl_case!(fmt_d0: "{:.0}" => "10");
815 impl_case!(fmt_d1: "{:.1}" => "10.0");
816 impl_case!(fmt_d2: "{:.2}" => "10.00");
817 }
818
819 mod dec_1en1 {
820 use super::*;
821
822 fn test_input() -> BigDecimal {
823 BigDecimal::new(1.into(), 1)
824 }
825
826 impl_case!(fmt_default: "{}" => "0.1");
827 impl_case!(fmt_d0: "{:.0}" => "0");
828 impl_case!(fmt_d1: "{:.1}" => "0.1");
829 impl_case!(fmt_d2: "{:.2}" => "0.10");
830 }
831
832 mod dec_9en1 {
833 use super::*;
834
835 fn test_input() -> BigDecimal {
836 BigDecimal::new(9.into(), 1)
837 }
838
839 impl_case!(fmt_default: "{}" => "0.9");
840 impl_case!(fmt_d0: "{:.0}" => "1");
841 impl_case!(fmt_d1: "{:.1}" => "0.9");
842 impl_case!(fmt_d4: "{:.4}" => "0.9000");
843 }
844
845 mod dec_800en3 {
846 use super::*;
847
848 fn test_input() -> BigDecimal {
849 BigDecimal::new(800.into(), 3)
850 }
851
852 impl_case!(fmt_default: "{}" => "0.800");
853 impl_case!(fmt_d0: "{:.0}" => "1");
854 impl_case!(fmt_d1: "{:.1}" => "0.8");
855 impl_case!(fmt_d3: "{:.3}" => "0.800");
856 impl_case!(fmt_d9: "{:.9}" => "0.800000000");
857 }
858
859 mod dec_123456 {
860 use super::*;
861
862 fn test_input() -> BigDecimal {
863 "123456".parse().unwrap()
864 }
865
866 impl_case!(fmt_default: "{}" => "123456");
867 impl_case!(fmt_d1: "{:.1}" => "123456.0");
868 impl_case!(fmt_d4: "{:.4}" => "123456.0000");
869 impl_case!(fmt_4d1: "{:4.1}" => "123456.0");
870 impl_case!(fmt_15d2: "{:15.2}" => " 123456.00");
871 impl_case!(fmt_r15d2: "{:>15.2}" => " 123456.00");
872 impl_case!(fmt_l15d2: "{:<15.2}" => "123456.00 ");
873 impl_case!(fmt_p05d1: "{:+05.7}" => "+123456.0000000");
874 }
875
876 mod dec_d099995 {
877 use super::*;
878
879 fn test_input() -> BigDecimal {
880 ".099995".parse().unwrap()
881 }
882
883 impl_case!(fmt_default: "{}" => "0.099995");
884 impl_case!(fmt_d0: "{:.0}" => "0");
885 impl_case!(fmt_d1: "{:.1}" => "0.1");
886 impl_case!(fmt_d3: "{:.3}" => "0.100");
887 }
888
889 mod dec_d9999999 {
890 use super::*;
891
892 fn test_input() -> BigDecimal {
893 ".9999999".parse().unwrap()
894 }
895
896 impl_case!(fmt_default: "{}" => "0.9999999");
897 impl_case!(fmt_d0: "{:.0}" => "1");
898 impl_case!(fmt_d1: "{:.1}" => "1.0");
899 impl_case!(fmt_d3: "{:.3}" => "1.000");
900 }
901
902 mod dec_9999999 {
903 use super::*;
904
905 fn test_input() -> BigDecimal {
906 "9999999".parse().unwrap()
907 }
908
909 impl_case!(fmt_default: "{}" => "9999999");
910 impl_case!(fmt_d1: "{:.1}" => "9999999.0");
911 impl_case!(fmt_d8: "{:.8}" => "9999999.00000000");
912
913 impl_case!(fmt_e: "{:e}" => "9.999999e+6");
914 impl_case!(fmt_E: "{:E}" => "9.999999E+6");
915 impl_case!(fmt_d0e: "{:.0e}" => "1e+7");
916 impl_case!(fmt_d1e: "{:.1e}" => "1.0e+7");
917 impl_case!(fmt_d2e: "{:.2e}" => "1.00e+7");
918 impl_case!(fmt_d4e: "{:.4e}" => "1.0000e+7");
919 impl_case!(fmt_d6e: "{:.6e}" => "9.999999e+6");
920 impl_case!(fmt_d7e: "{:.7e}" => "9.9999990e+6");
921 impl_case!(fmt_d10e: "{:.10e}" => "9.9999990000e+6");
922 }
923
924 mod dec_19073d97235939614856 {
925 use super::*;
926
927 fn test_input() -> BigDecimal {
928 "19073.97235939614856".parse().unwrap()
929 }
930
931 impl_case!(fmt_default: "{}" => "19073.97235939614856");
932 impl_case!(fmt_pd7: "{:+.7}" => "+19073.9723594");
933 impl_case!(fmt_d0: "{:.0}" => "19074");
934 impl_case!(fmt_d1: "{:.1}" => "19074.0");
935 impl_case!(fmt_d3: "{:.3}" => "19073.972");
936 impl_case!(fmt_d4: "{:.4}" => "19073.9724");
937 impl_case!(fmt_8d3: "{:8.3}" => "19073.972");
938 impl_case!(fmt_10d3: "{:10.3}" => " 19073.972");
939 impl_case!(fmt_010d3: "{:010.3}" => "019073.972");
940 }
941
942 mod dec_10950633712399d557 {
943 use super::*;
944
945 fn test_input() -> BigDecimal {
946 "10950633712399.557".parse().unwrap()
947 }
948
949 impl_case!(fmt_default: "{}" => "10950633712399.557");
950 impl_case!(fmt_d0: "{:.0}" => "10950633712400");
951 impl_case!(fmt_d1: "{:.1}" => "10950633712399.6");
952 impl_case!(fmt_d2: "{:.2}" => "10950633712399.56");
953 impl_case!(fmt_d3: "{:.3}" => "10950633712399.557");
954 impl_case!(fmt_d4: "{:.4}" => "10950633712399.5570");
955 }
956
957 mod dec_n90037659d6902 {
958 use super::*;
959
960 fn test_input() -> BigDecimal {
961 "-90037659.6905".parse().unwrap()
962 }
963
964 impl_case!(fmt_default: "{}" => "-90037659.6905");
965 impl_case!(fmt_debug: "{:?}" => "BigDecimal(sign=Minus, scale=4, digits=[900376596905])");
966 impl_case!(fmt_debug_alt: "{:#?}" => "BigDecimal(\"-900376596905e-4\")");
967 impl_case!(fmt_pd7: "{:+.7}" => "-90037659.6905000");
968 impl_case!(fmt_d0: "{:.0}" => "-90037660");
969 impl_case!(fmt_d3: "{:.3}" => "-90037659.690");
970 impl_case!(fmt_d4: "{:.4}" => "-90037659.6905");
971 impl_case!(fmt_14d4: "{:14.4}" => "-90037659.6905");
972 impl_case!(fmt_15d4: "{:15.4}" => " -90037659.6905");
973 impl_case!(fmt_l17d5: "{:<17.5}" => "-90037659.69050 ");
974 }
975
976 mod dec_0d0002394899999500 {
977 use super::*;
978
979 fn test_input() -> BigDecimal {
980 "0.0002394899999500".parse().unwrap()
981 }
982
983 impl_case!(fmt_default: "{}" => "0.0002394899999500");
984 impl_case!(fmt_d0: "{:.0}" => "0");
985 impl_case!(fmt_d1: "{:.1}" => "0.0");
986 impl_case!(fmt_d3: "{:.3}" => "0.000");
987 impl_case!(fmt_d4: "{:.4}" => "0.0002");
988 impl_case!(fmt_d5: "{:.5}" => "0.00024");
989 impl_case!(fmt_d10: "{:.10}" => "0.0002394900");
990 impl_case!(fmt_d13: "{:.13}" => "0.0002394900000");
991 impl_case!(fmt_d14: "{:.14}" => "0.00023948999995");
992 impl_case!(fmt_d20: "{:.20}" => "0.00023948999995000000");
993
994 }
995
996 mod dec_1764031078en13 {
997 use super::*;
998
999 fn test_input() -> BigDecimal {
1000 BigDecimal::new(1764031078.into(), 13)
1001 }
1002
1003 impl_case!(fmt_default: "{}" => "0.0001764031078");
1004 impl_case!(fmt_d1: "{:.1}" => "0.0");
1005 impl_case!(fmt_d3: "{:.3}" => "0.000");
1006 impl_case!(fmt_d4: "{:.4}" => "0.0002");
1007 impl_case!(fmt_d5: "{:.5}" => "0.00018");
1008 impl_case!(fmt_d13: "{:.13}" => "0.0001764031078");
1009 impl_case!(fmt_d20: "{:.20}" => "0.00017640310780000000");
1010
1011 }
1012
1013 mod dec_1e15 {
1014 use super::*;
1015
1016 fn test_input() -> BigDecimal {
1017 "1e15".parse().unwrap()
1018 }
1019
1020 impl_case!(fmt_default: "{}" => "1000000000000000");
1021 impl_case!(fmt_d0: "{:.0}" => "1000000000000000");
1022 impl_case!(fmt_d1: "{:.1}" => "1000000000000000.0");
1023 }
1024
1025 mod dec_1e16 {
1026 use super::*;
1027
1028 fn test_input() -> BigDecimal {
1029 "1e16".parse().unwrap()
1030 }
1031
1032 impl_case!(fmt_default: "{}" => "1e+16");
1033 impl_case!(fmt_d0: "{:.0}" => "10000000000000000");
1034 impl_case!(fmt_d2: "{:.2}" => "10000000000000000.00");
1035 }
1036
1037
1038 mod dec_491326en12 {
1039 use super::*;
1040
1041 fn test_input() -> BigDecimal {
1042 "491326e-12".parse().unwrap()
1043 }
1044
1045 impl_case!(fmt_default: "{}" => "4.91326E-7");
1046 impl_case!(fmt_d0: "{:.0}" => "0");
1047 impl_case!(fmt_d1: "{:.1}" => "0.0");
1048 impl_case!(fmt_d3: "{:.3}" => "0.000");
1049 impl_case!(fmt_d5: "{:.5}" => "0.00000");
1050 impl_case!(fmt_d6: "{:.7}" => "0.0000005");
1051 impl_case!(fmt_d9: "{:.9}" => "0.000000491");
1052 impl_case!(fmt_d20: "{:.20}" => "0.00000049132600000000");
1053
1054 impl_case!(fmt_d0e: "{:.0E}" => "5E-7");
1055 impl_case!(fmt_d1e: "{:.1E}" => "4.9E-7");
1056 impl_case!(fmt_d3e: "{:.3E}" => "4.913E-7");
1057 impl_case!(fmt_d5e: "{:.5E}" => "4.91326E-7");
1058 impl_case!(fmt_d6e: "{:.6E}" => "4.913260E-7");
1059 }
1060
1061 mod dec_0d00003102564500 {
1062 use super::*;
1063
1064 fn test_input() -> BigDecimal {
1065 "0.00003102564500".parse().unwrap()
1066 }
1067
1068 impl_case!(fmt_default: "{}" => "0.00003102564500");
1069 impl_case!(fmt_d0: "{:.0}" => "0");
1070 impl_case!(fmt_d1: "{:.1}" => "0.0");
1071 impl_case!(fmt_d2: "{:.2}" => "0.00");
1072 impl_case!(fmt_d4: "{:.4}" => "0.0000");
1073 impl_case!(fmt_d5: "{:.5}" => "0.00003");
1074 impl_case!(fmt_d10: "{:.10}" => "0.0000310256");
1075 impl_case!(fmt_d14: "{:.14}" => "0.00003102564500");
1076 impl_case!(fmt_d17: "{:.17}" => "0.00003102564500000");
1077
1078 impl_case!(fmt_e: "{:e}" => "3.102564500e-5");
1079 impl_case!(fmt_de: "{:.e}" => "3.102564500e-5");
1080 impl_case!(fmt_d0e: "{:.0e}" => "3e-5");
1081 impl_case!(fmt_d1e: "{:.1e}" => "3.1e-5");
1082 impl_case!(fmt_d4e: "{:.4e}" => "3.1026e-5");
1083 }
1084
1085 mod dec_1en100000 {
1086 use super::*;
1087
1088 fn test_input() -> BigDecimal {
1089 "1E-10000".parse().unwrap()
1090 }
1091
1092 impl_case!(fmt_default: "{}" => "1E-10000");
1093 impl_case!(fmt_d: "{:.0}" => "0");
1094 impl_case!(fmt_d1: "{:.1}" => "0.0");
1095 impl_case!(fmt_d4: "{:.4}" => "0.0000");
1096
1097 impl_case!(fmt_d1E: "{:.1E}" => "1.0E-10000");
1098 impl_case!(fmt_d4E: "{:.4E}" => "1.0000E-10000");
1099 }
1100
1101 mod dec_1e100000 {
1102 use super::*;
1103
1104 fn test_input() -> BigDecimal {
1105 "1e100000".parse().unwrap()
1106 }
1107
1108 impl_case!(fmt_default: "{}" => "1e+100000");
1109 impl_case!(fmt_d1: "{:.1}" => "1e+100000");
1110 impl_case!(fmt_d4: "{:.4}" => "1e+100000");
1111 }
1112
1113
1114 mod dec_1234506789E5 {
1115 use super::*;
1116
1117 fn test_input() -> BigDecimal {
1118 BigDecimal::new(1234506789.into(), -5)
1119 }
1120
1121 impl_case!(fmt_default: "{}" => "123450678900000");
1122 impl_case!(fmt_d1: "{:.1}" => "123450678900000.0");
1123 impl_case!(fmt_d3: "{:.3}" => "123450678900000.000");
1124 impl_case!(fmt_d4: "{:.4}" => "123450678900000.0000");
1125 impl_case!(fmt_l13d4: "{:<23.4}" => "123450678900000.0000 ");
1126 impl_case!(fmt_r13d4: "{:>23.4}" => " 123450678900000.0000");
1127 }
1128
1129 mod dec_1234506789E15 {
1130 use super::*;
1131
1132 fn test_input() -> BigDecimal {
1133 BigDecimal::new(1234506789.into(), -15)
1134 }
1135
1136 impl_case!(fmt_default: "{}" => "1234506789000000000000000");
1137 impl_case!(fmt_d1: "{:.1}" => "1234506789000000000000000.0");
1138 impl_case!(fmt_d3: "{:.3}" => "1234506789000000000000000.000");
1139 impl_case!(fmt_l13d4: "{:<+32.2}" => "+1234506789000000000000000.00 ");
1140 impl_case!(fmt_r13d4: "{:>+32.2}" => " +1234506789000000000000000.00");
1141 }
1142
1143 mod dec_13400476439814628800E2502 {
1144 use super::*;
1145
1146 fn test_input() -> BigDecimal {
1147 BigDecimal::new(13400476439814628800u64.into(), -2502)
1148 }
1149
1150 impl_case!(fmt_default: "{}" => "13400476439814628800e+2502");
1151 impl_case!(fmt_d1: "{:.1}" => "13400476439814628800e+2502");
1152 }
1153
1154 mod dec_d9999 {
1155 use super::*;
1156
1157 fn test_input() -> BigDecimal {
1158 "0.9999".parse().unwrap()
1159 }
1160
1161 impl_case!(fmt_default: "{}" => "0.9999");
1162 impl_case!(fmt_d0: "{:.0}" => "1");
1163 impl_case!(fmt_d1: "{:.1}" => "1.0");
1164 impl_case!(fmt_d2: "{:.2}" => "1.00");
1165 impl_case!(fmt_d3: "{:.3}" => "1.000");
1166 impl_case!(fmt_d4: "{:.4}" => "0.9999");
1167 impl_case!(fmt_d6: "{:.6}" => "0.999900");
1168 }
1169
1170 mod dec_9d99 {
1171 use super::*;
1172
1173 fn test_input() -> BigDecimal {
1174 "9.99".parse().unwrap()
1175 }
1176
1177 impl_case!(fmt_default: "{}" => "9.99");
1178 impl_case!(fmt_d0: "{:.0}" => "10");
1179 impl_case!(fmt_d1: "{:.1}" => "10.0");
1180 impl_case!(fmt_d2: "{:.2}" => "9.99");
1181 impl_case!(fmt_d3: "{:.3}" => "9.990");
1182 impl_case!(fmt_10d3: "{:10.3}" => " 9.990");
1183 }
1184
1185 mod dec_0 {
1186 use super::*;
1187
1188 fn test_input() -> BigDecimal {
1189 "0".parse().unwrap()
1190 }
1191
1192 impl_case!(fmt_default: "{}" => "0");
1193 impl_case!(fmt_d0: "{:.0}" => "0");
1194 impl_case!(fmt_d1: "{:.1}" => "0.0");
1195
1196 impl_case!(fmt_e: "{:e}" => "0e+0");
1197 impl_case!(fmt_E: "{:E}" => "0E+0");
1198 }
1199
1200 mod dec_0e15 {
1201 use super::*;
1202
1203 fn test_input() -> BigDecimal {
1204 "0e15".parse().unwrap()
1205 }
1206
1207 impl_case!(fmt_default: "{}" => "0");
1208 impl_case!(fmt_d0: "{:.0}" => "0");
1209 impl_case!(fmt_d1: "{:.1}" => "0.0");
1210 impl_case!(fmt_5d1: "{:5.1}" => " 0.0");
1211 impl_case!(fmt_010d1: "{:010.1}" => "00000000.0");
1212
1213 impl_case!(fmt_e: "{:e}" => "0e+0");
1214 impl_case!(fmt_E: "{:E}" => "0E+0");
1215
1216 impl_case!(fmt_d2e: "{:.2e}" => "0.00e+0");
1217 impl_case!(fmt_8d2e: "{:8.2e}" => " 0.00e+0");
1218 }
1219
1220 mod dec_0en15 {
1221 use super::*;
1222
1223 fn test_input() -> BigDecimal {
1224 "0e-15".parse().unwrap()
1225 }
1226
1227 impl_case!(fmt_default: "{}" => "0");
1228 impl_case!(fmt_d0: "{:.0}" => "0");
1229 impl_case!(fmt_d1: "{:.1}" => "0.0");
1230 impl_case!(fmt_6d2: "{:6.2}" => " 0.00");
1231 impl_case!(fmt_010d1: "{:010.1}" => "00000000.0");
1232
1233 impl_case!(fmt_e: "{:e}" => "0e+0");
1234 impl_case!(fmt_E: "{:E}" => "0E+0");
1235 }
1236
1237 mod dec_n0e6 {
1238 use super::*;
1239
1240 fn test_input() -> BigDecimal {
1241 "-0e6".parse().unwrap()
1242 }
1243
1244 impl_case!(fmt_default: "{}" => "0");
1245 impl_case!(fmt_d1: "{:.1}" => "0.0");
1246
1247 impl_case!(fmt_e: "{:e}" => "0e+0");
1248 impl_case!(fmt_E: "{:E}" => "0E+0");
1249 }
1250 }
1251
1252 mod fmt_boundaries {
1253 use super::*;
1254
1255 macro_rules! impl_case {
1256 ( $name:ident: $src:expr => $expected:literal ) => {
1257 #[test]
1258 fn $name() {
1259 let src = $src;
1260 let bd: BigDecimal = src.parse().unwrap();
1261 let result = bd.to_string();
1262 assert_eq!(result, $expected);
1263
1264 let round_trip = BigDecimal::from_str(&result).unwrap();
1265 assert_eq!(round_trip, bd);
1266
1267 let sci = bd.to_scientific_notation();
1268 let sci_round_trip = BigDecimal::from_str(&sci).unwrap();
1269 assert_eq!(sci_round_trip, bd);
1270
1271 let eng = bd.to_engineering_notation();
1272 let eng_round_trip = BigDecimal::from_str(&eng).unwrap();
1273 assert_eq!(eng_round_trip, bd);
1274 }
1275 };
1276 ( (eng-check-invalid) $name:ident: $src:expr => $expected:literal ) => {
1277 #[test]
1278 fn $name() {
1279 let src = $src;
1280 let bd: BigDecimal = src.parse().unwrap();
1281 let result = bd.to_string();
1282 assert_eq!(result, $expected);
1283
1284 let round_trip = BigDecimal::from_str(&result).unwrap();
1285 assert_eq!(round_trip, bd);
1286
1287 let sci = bd.to_scientific_notation();
1288 let sci_round_trip = BigDecimal::from_str(&sci).unwrap();
1289 assert_eq!(sci_round_trip, bd);
1290
1291 let eng = bd.to_engineering_notation();
1292 let eng_round_trip = BigDecimal::from_str(&eng);
1293 assert!(eng_round_trip.is_err());
1294 }
1295 };
1296 ( (panics) $name:ident: $src:expr ) => {
1297 #[test]
1298 #[should_panic]
1299 fn $name() {
1300 let src = $src;
1301 let _bd: BigDecimal = src.parse().unwrap();
1302 }
1303 };
1304 }
1305
1306
1307 impl_case!(test_max: format!("1E{}", i64::MAX) => "1e+9223372036854775807");
1308 impl_case!(test_max_multiple_digits: format!("314156E{}", i64::MAX) => "314156e+9223372036854775807");
1309 impl_case!(test_min_scale: "1E9223372036854775807" => "1e+9223372036854775807");
1310
1311 impl_case!((eng-check-invalid) test_max_scale: "1E-9223372036854775807" => "1E-9223372036854775807");
1312 impl_case!(test_min_multiple_digits: format!("271828182E-{}", i64::MAX) => "2.71828182E-9223372036854775799");
1313
1314 impl_case!((panics) test_max_exp_overflow: "1E9223372036854775809");
1315 impl_case!((panics) test_min_exp_overflow: "1E-9223372036854775808");
1316 }
1317
1318 #[test]
1319 fn test_fmt() {
1320 let vals = vec![
1321 (1, 0, ( "1", "1.0", "1.0000", " 1.0", "+01.0", "1.0 " )),
1323 (1, 1, ( "0.1", "0.1", "0.1000", " 0.1", "+00.1", "0.1 " )),
1324 (1, 2, ( "0.01", "0.0", "0.0100", " 0.0", "+00.0", "0.0 " )),
1325 (1, -2, ( "100", "100.0", "100.0000", "100.0", "+100.0", "100.0" )),
1326 (-1, 0, ( "-1", "-1.0", "-1.0000", "-1.0", "-01.0", "-1.0" )),
1327 (-1, 1, ( "-0.1", "-0.1", "-0.1000", "-0.1", "-00.1", "-0.1" )),
1328 (-1, 2, ( "-0.01", "-0.0", "-0.0100", "-0.0", "-00.0", "-0.0" )),
1329 ];
1330 for (i, scale, results) in vals {
1331 let x = BigDecimal::new(num_bigint::BigInt::from(i), scale);
1332 assert_eq!(format!("{}", x), results.0);
1333 assert_eq!(format!("{:.1}", x), results.1);
1334 assert_eq!(format!("{:.4}", x), results.2);
1335 assert_eq!(format!("{:4.1}", x), results.3);
1336 assert_eq!(format!("{:+05.1}", x), results.4);
1337 assert_eq!(format!("{:<4.1}", x), results.5);
1338 }
1339 }
1340
1341
1342 mod fmt_debug {
1343 use super::*;
1344
1345 macro_rules! impl_case {
1346 ($name:ident: $input:literal => $expected:literal => $expected_alt:literal) => {
1347 paste! {
1348 #[test]
1349 fn $name() {
1350 let x: BigDecimal = $input.parse().unwrap();
1351 let y = format!("{:?}", x);
1352 assert_eq!(y, $expected);
1353 }
1354
1355 #[test]
1356 fn [< $name _alt >]() {
1357 let x: BigDecimal = $input.parse().unwrap();
1358 let y = format!("{:#?}", x);
1359 assert_eq!(y, $expected_alt);
1360 }
1361 }
1362 };
1363 }
1364
1365 impl_case!(case_0: "0" => r#"BigDecimal(sign=NoSign, scale=0, digits=[])"#
1366 => r#"BigDecimal("0e0")"#);
1367
1368 impl_case!(case_n0: "-0" => r#"BigDecimal(sign=NoSign, scale=0, digits=[])"#
1369 => r#"BigDecimal("0e0")"#);
1370
1371 impl_case!(case_1: "1" => r#"BigDecimal(sign=Plus, scale=0, digits=[1])"#
1372 => r#"BigDecimal("1e0")"#);
1373
1374 impl_case!(case_123_400: "123.400" => r#"BigDecimal(sign=Plus, scale=3, digits=[123400])"#
1375 => r#"BigDecimal("123400e-3")"#);
1376
1377 impl_case!(case_123_4en2: "123.4e-2" => r#"BigDecimal(sign=Plus, scale=3, digits=[1234])"#
1378 => r#"BigDecimal("1234e-3")"#);
1379
1380 impl_case!(case_123_456: "123.456" => r#"BigDecimal(sign=Plus, scale=3, digits=[123456])"#
1381 => r#"BigDecimal("123456e-3")"#);
1382
1383 impl_case!(case_01_20: "01.20" => r#"BigDecimal(sign=Plus, scale=2, digits=[120])"#
1384 => r#"BigDecimal("120e-2")"#);
1385
1386 impl_case!(case_1_20: "1.20" => r#"BigDecimal(sign=Plus, scale=2, digits=[120])"#
1387 => r#"BigDecimal("120e-2")"#);
1388 impl_case!(case_01_2e3: "01.2E3" => r#"BigDecimal(sign=Plus, scale=-2, digits=[12])"#
1389 => r#"BigDecimal("12e2")"#);
1390
1391 impl_case!(case_avagadro: "6.02214076e1023" => r#"BigDecimal(sign=Plus, scale=-1015, digits=[602214076])"#
1392 => r#"BigDecimal("602214076e1015")"#);
1393
1394 impl_case!(case_1e99999999999999 : "1e99999999999999" => r#"BigDecimal(sign=Plus, scale=-99999999999999, digits=[1])"#
1395 => r#"BigDecimal("1e99999999999999")"#);
1396
1397 impl_case!(case_n144d3308279 : "-144.3308279" => r#"BigDecimal(sign=Minus, scale=7, digits=[1443308279])"#
1398 => r#"BigDecimal("-1443308279e-7")"#);
1399
1400 impl_case!(case_n349983058835858339619e2 : "-349983058835858339619e2"
1401 => r#"BigDecimal(sign=Minus, scale=-2, digits=[17941665509086410531, 18])"#
1402 => r#"BigDecimal("-349983058835858339619e2")"#);
1403 }
1404
1405 mod write_scientific_notation {
1406 use super::*;
1407
1408 macro_rules! test_fmt_function {
1409 ($n:expr) => { $n.to_scientific_notation() };
1410 }
1411
1412 impl_case!(case_4_1592480782835e9 : "4159248078.2835" => "4.1592480782835e9");
1413 impl_case!(case_1_234e_5 : "0.00001234" => "1.234e-5");
1414 impl_case!(case_0 : "0" => "0e0");
1415 impl_case!(case_1 : "1" => "1e0");
1416 impl_case!(case_2_00e0 : "2.00" => "2.00e0");
1417 impl_case!(case_neg_5_70e1 : "-57.0" => "-5.70e1");
1418 }
1419
1420 mod write_engineering_notation {
1421 use super::*;
1422
1423 macro_rules! test_fmt_function {
1424 ($n:expr) => { $n.to_engineering_notation() };
1425 }
1426
1427 impl_case!(case_4_1592480782835e9 : "4159248078.2835" => "4.1592480782835e9");
1428 impl_case!(case_12_34e_6 : "0.00001234" => "12.34e-6");
1429 impl_case!(case_0 : "0" => "0e0");
1430 impl_case!(case_1 : "1" => "1e0");
1431 impl_case!(case_2_00e0 : "2.00" => "2.00e0");
1432 impl_case!(case_neg_5_70e1 : "-57.0" => "-57.0e0");
1433 impl_case!(case_5_31e4 : "5.31e4" => "53.1e3");
1434 impl_case!(case_5_31e5 : "5.31e5" => "531e3");
1435 impl_case!(case_5_31e6 : "5.31e6" => "5.31e6");
1436 impl_case!(case_5_31e7 : "5.31e7" => "53.1e6");
1437
1438 impl_case!(case_1e2 : "1e2" => "100e0");
1439 impl_case!(case_1e119 : "1e19" => "10e18");
1440 impl_case!(case_1e3000 : "1e3000" => "1e3000");
1441 impl_case!(case_4_2e7 : "4.2e7" => "42e6");
1442 impl_case!(case_4_2e8 : "4.2e8" => "420e6");
1443
1444 impl_case!(case_4e99999999999999 : "4e99999999999999" => "4e99999999999999");
1445 impl_case!(case_4e99999999999998 : "4e99999999999998" => "400e99999999999996");
1446 impl_case!(case_44e99999999999998 : "44e99999999999998" => "4.4e99999999999999");
1447 impl_case!(case_4e99999999999997 : "4e99999999999997" => "40e99999999999996");
1448 impl_case!(case_41e99999999999997 : "41e99999999999997" => "410e99999999999996");
1449 impl_case!(case_413e99999999999997 : "413e99999999999997" => "4.13e99999999999999");
1450 }
1452}
1453
1454
1455#[cfg(all(test, property_tests))]
1456mod proptests {
1457 use super::*;
1458 use paste::paste;
1459 use proptest::prelude::*;
1460 use proptest::num::f64::NORMAL as NormalF64;
1461
1462
1463 macro_rules! impl_parsing_test {
1464 ($t:ty) => {
1465 paste! { proptest! {
1466 #[test]
1467 fn [< roudtrip_to_str_and_back_ $t >](n: $t) {
1468 let original = BigDecimal::from(n);
1469 let display = format!("{}", original);
1470 let parsed = display.parse::<BigDecimal>().unwrap();
1471
1472 prop_assert_eq!(&original, &parsed);
1473 }
1474 } }
1475 };
1476 (from-float $t:ty) => {
1477 paste! { proptest! {
1478 #[test]
1479 fn [< roudtrip_to_str_and_back_ $t >](n: $t) {
1480 let original = BigDecimal::try_from(n).unwrap();
1481 let display = format!("{}", original);
1482 let parsed = display.parse::<BigDecimal>().unwrap();
1483
1484 prop_assert_eq!(&original, &parsed);
1485 }
1486 } }
1487 };
1488 }
1489
1490 impl_parsing_test!(u8);
1491 impl_parsing_test!(u16);
1492 impl_parsing_test!(u32);
1493 impl_parsing_test!(u64);
1494 impl_parsing_test!(u128);
1495
1496 impl_parsing_test!(i8);
1497 impl_parsing_test!(i16);
1498 impl_parsing_test!(i32);
1499 impl_parsing_test!(i64);
1500 impl_parsing_test!(i128);
1501
1502 impl_parsing_test!(from-float f32);
1503 impl_parsing_test!(from-float f64);
1504
1505 proptest! {
1506 #![proptest_config(ProptestConfig::with_cases(32_000))]
1507
1508 #[test]
1509 fn float_formatting(f in NormalF64, prec in 0..21usize) {
1510 let d = BigDecimal::from_f64(f).unwrap();
1511 let f_fmt = format!("{f:.prec$}");
1512 let d_fmt = format!("{d:.prec$}").replace("+", "");
1513 prop_assert_eq!(f_fmt, d_fmt);
1514 }
1515 }
1516
1517 proptest! {
1518 #![proptest_config(ProptestConfig::with_cases(1000))]
1519
1520 #[test]
1521 fn scientific_notation_roundtrip(f: f64) {
1522 prop_assume!(!f.is_nan() && !f.is_infinite());
1523 let n = BigDecimal::from_f64(f).unwrap();
1524 let s = n.to_scientific_notation();
1525 let m: BigDecimal = s.parse().unwrap();
1526 prop_assert_eq!(n, m);
1527 }
1528
1529 #[test]
1530 fn engineering_notation_roundtrip(f: f64) {
1531 prop_assume!(!f.is_nan() && !f.is_infinite());
1532 let n = BigDecimal::from_f64(f).unwrap();
1533 let s = n.to_engineering_notation();
1534 let m: BigDecimal = s.parse().unwrap();
1535 prop_assert_eq!(n, m);
1536 }
1537 }
1538}