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