Skip to content

Commit

Permalink
Make Display for Decimal more human-friendly
Browse files Browse the repository at this point in the history
  • Loading branch information
jobarr-amzn committed Mar 10, 2023
1 parent e3f7bd1 commit d8b9b26
Showing 1 changed file with 36 additions and 9 deletions.
45 changes: 36 additions & 9 deletions src/types/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,35 @@ impl TryFrom<f64> for Decimal {

impl Display for Decimal {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
// TODO: This is correct, but not the most human-friendly format.
write!(f, "{}d{}", self.coefficient, self.exponent)
let digits = &*self.coefficient.magnitude.to_string();
let precision = digits.len();
let decimal_index= precision as i64 + self.exponent;
// fallback to scientific notation if (exponent - precision) > X?

if self.coefficient.sign == Sign::Negative {
write!(f, "-").unwrap();
};

if self.exponent > 6 { // e.g. A.BCd12
write!(f, "{}.{}d{}", &digits[0..1], &digits[1..precision], (decimal_index - 1))
} else if self.exponent > 0 { // e.g. ABC0000. or ABC.
let zeroes = "0".repeat(self.exponent as usize);
write!(f, "{}{}.", &digits, &*zeroes)
} else { // implies a fractional component
if decimal_index > 0 { // e.g. A.BC or AB.C
let i = decimal_index as usize;
write!(f, "{}.{}", &digits[0..i], &digits[i..precision])
} else if decimal_index > -6 { // e.g. 0.ABC or 0.000ABC
let zeroes = "0".repeat(decimal_index.abs() as usize);
write!(f, "0.{}{}", &*zeroes, &digits)
} else { // e.g. A.BCd-12
write!(f, "{}.{}d{}", &digits[0..1], &digits[1..precision], (decimal_index - 1))
}
}
}
}


/// Make a Decimal from a BigDecimal. This is a lossless operation.
impl From<BigDecimal> for Decimal {
fn from(value: BigDecimal) -> Self {
Expand Down Expand Up @@ -347,12 +371,15 @@ mod decimal_tests {
use rstest::*;

#[rstest]
#[case(Decimal::new(1, 0), "1d0")]
#[case(Decimal::new(123, -2), "123d-2")]
#[case(Decimal::new(123, 2), "123d2")]
#[case(Decimal::negative_zero_with_exponent(0), "-0d0")]
#[case(Decimal::negative_zero_with_exponent(-4), "-0d-4")]
#[case(Decimal::negative_zero_with_exponent(4), "-0d4")]
#[case(Decimal::new( 123, 7), "1.23d9")]
#[case(Decimal::new( 123, 0), "123.")]
#[case(Decimal::new(-123, 0),"-123.")]
#[case(Decimal::new( 123, -1), "12.3")]
#[case(Decimal::new( 123, -3), "0.123")]
#[case(Decimal::new(-123, -5), "-0.00123")]
#[case(Decimal::new( 123, -5), "0.00123")]
#[case(Decimal::new( 123, -10), "1.23d-8")]
#[case(Decimal::new(-123, -10), "-1.23d-8")]
fn test_display(#[case] decimal: Decimal, #[case] expected: &str) {
let mut buffer = String::new();
write!(buffer, "{decimal}").unwrap();
Expand Down Expand Up @@ -521,4 +548,4 @@ mod decimal_tests {
fn test_precision(#[case] value: Decimal, #[case] expected: u64) {
assert_eq!(value.precision(), expected);
}
}
}

0 comments on commit d8b9b26

Please sign in to comment.