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