Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 55 additions & 4 deletions common/src/float_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,32 @@ pub fn format_exponent(precision: usize, magnitude: f64, case: Case) -> String {
}
}

/// If s represents a floating point value, trailing zeros and a possibly trailing
/// decimal point will be removed.
/// This function does NOT work with decimal commas.
fn remove_trailing_redundant_chars(s: String) -> String {
if s.contains('.') {
// only truncate floating point values
let s = remove_trailing_zeros(s);
remove_trailing_decimal_point(s)
} else {
s
}
}

fn remove_trailing_zeros(s: String) -> String {
let mut s = s;
while s.ends_with('0') || s.ends_with('.') {
s.truncate(s.len() - 1);
while s.ends_with('0') {
s.pop();
}
s
}

fn remove_trailing_decimal_point(s: String) -> String {
let mut s = s;
if s.ends_with('.') {
s.pop();
}
s
}

Expand All @@ -159,12 +179,12 @@ pub fn format_general(precision: usize, magnitude: f64, case: Case) -> String {
Case::Upper => 'E',
};

let base = remove_trailing_zeros(format!("{:.*}", precision + 1, base));
let base = remove_trailing_redundant_chars(format!("{:.*}", precision + 1, base));
format!("{}{}{:+#03}", base, e, exponent)
} else {
let precision = (precision as i64) - 1 - exponent;
let precision = precision as usize;
remove_trailing_zeros(format!("{:.*}", precision, magnitude))
remove_trailing_redundant_chars(format!("{:.*}", precision, magnitude))
}
}
magnitude if magnitude.is_nan() => format_nan(case),
Expand Down Expand Up @@ -362,3 +382,34 @@ fn test_to_hex() {
assert!(f == roundtrip, "{} {} {}", f, hex, roundtrip);
}
}

#[test]
fn test_remove_trailing_zeros() {
assert!(remove_trailing_zeros(String::from("100")) == String::from("1"));
assert!(remove_trailing_zeros(String::from("100.00")) == String::from("100."));

// leave leading zeros untouched
assert!(remove_trailing_zeros(String::from("001")) == String::from("001"));

// leave strings untouched if they don't end with 0
assert!(remove_trailing_zeros(String::from("101")) == String::from("101"));
}

#[test]
fn test_remove_trailing_decimal_point() {
assert!(remove_trailing_decimal_point(String::from("100.")) == String::from("100"));
assert!(remove_trailing_decimal_point(String::from("1.")) == String::from("1"));

// leave leading decimal points untouched
assert!(remove_trailing_decimal_point(String::from(".5")) == String::from(".5"));
}

#[test]
fn test_remove_trailing_redundant_chars() {
assert!(remove_trailing_redundant_chars(String::from("100.")) == String::from("100"));
assert!(remove_trailing_redundant_chars(String::from("1.")) == String::from("1"));
assert!(remove_trailing_redundant_chars(String::from("10.0")) == String::from("10"));

// don't truncate integers
assert!(remove_trailing_redundant_chars(String::from("1000")) == String::from("1000"));
}
4 changes: 3 additions & 1 deletion extra_tests/snippets/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,8 @@ def try_mutate_str():
assert '{:E}'.format(float('inf')) == 'INF'

# Test g & G formatting
assert '{:g}'.format(10.0) == '10'
assert '{:g}'.format(100000.0) == '100000'
assert '{:g}'.format(123456.78901234567890) == '123457'
assert '{:.0g}'.format(123456.78901234567890) == '1e+05'
assert '{:.1g}'.format(123456.78901234567890) == '1e+05'
Expand Down Expand Up @@ -699,4 +701,4 @@ def test_removesuffix_types():
skip_if_unsupported(3,9,test_removeprefix)
skip_if_unsupported(3,9,test_removeprefix_types)
skip_if_unsupported(3,9,test_removesuffix)
skip_if_unsupported(3,9,test_removesuffix_types)
skip_if_unsupported(3,9,test_removesuffix_types)