Files
wson-rs/src/text/float_fmt.rs
T

91 lines
2.8 KiB
Rust

/// Formats `f64` with Java `Double.toString` semantics as closely as Rust's
/// shortest-roundtrip formatting allows.
pub fn format_java_double(value: f64) -> String {
if value.is_nan() {
return "NaN".to_string();
}
if value == f64::INFINITY {
return "Infinity".to_string();
}
if value == f64::NEG_INFINITY {
return "-Infinity".to_string();
}
if value == 0.0 {
return if value.is_sign_negative() {
"-0.0".to_string()
} else {
"0.0".to_string()
};
}
let scientific = format!("{value:e}");
let (mantissa, exp) = scientific
.split_once('e')
.expect("lowerexp formatting always contains e");
let exponent: i32 = exp.parse().expect("lowerexp exponent is an integer");
let negative = mantissa.starts_with('-');
let mantissa = mantissa.trim_start_matches('-');
let digits: String = mantissa.chars().filter(|c| *c != '.').collect();
// Java uses plain decimal notation for 1e-3 <= abs(value) < 1e7.
if (-3..7).contains(&exponent) {
let point_pos = exponent + 1;
let mut out = String::new();
if negative {
out.push('-');
}
if point_pos <= 0 {
out.push_str("0.");
for _ in 0..(-point_pos) {
out.push('0');
}
out.push_str(&digits);
} else if point_pos as usize >= digits.len() {
out.push_str(&digits);
for _ in 0..(point_pos as usize - digits.len()) {
out.push('0');
}
out.push_str(".0");
} else {
let split = point_pos as usize;
out.push_str(&digits[..split]);
out.push('.');
out.push_str(&digits[split..]);
}
out
} else {
let mut out = String::new();
if negative {
out.push('-');
}
out.push(digits.as_bytes()[0] as char);
out.push('.');
if digits.len() == 1 {
out.push('0');
} else {
out.push_str(&digits[1..]);
}
out.push('E');
out.push_str(&exponent.to_string());
out
}
}
#[cfg(test)]
mod tests {
use super::format_java_double;
#[test]
fn java_double_formatting() {
assert_eq!(format_java_double(1.0), "1.0");
assert_eq!(format_java_double(36.0), "36.0");
assert_eq!(format_java_double(0.001), "0.001");
assert_eq!(format_java_double(0.0001), "1.0E-4");
assert_eq!(format_java_double(9_999_999.0), "9999999.0");
assert_eq!(format_java_double(10_000_000.0), "1.0E7");
assert_eq!(format_java_double(1e22), "1.0E22");
assert_eq!(format_java_double(1e-7), "1.0E-7");
assert_eq!(format_java_double(-2.5), "-2.5");
}
}