91 lines
2.8 KiB
Rust
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");
|
|
}
|
|
}
|