1pub fn format_number(value: f64) -> String {
15 if !value.is_finite() {
16 return format!("{value}");
17 }
18 if value == 0.0 {
19 return "0".to_string();
20 }
21 let rounded = value.round();
22 let near_integer = (value - rounded).abs() <= f64::EPSILON * value.abs().max(1.0) * 4.0;
23 if near_integer && rounded.abs() < 1e15 {
24 return format!("{}", rounded as i64);
25 }
26 truncate_significant(&format!("{value}"), 16)
27}
28
29fn truncate_significant(text: &str, max_digits: usize) -> String {
32 let (mantissa, exponent) = match text.find('e').or_else(|| text.find('E')) {
33 Some(index) => {
34 let exponent: i32 = text[index + 1..].parse().unwrap_or(0);
35 (&text[..index], exponent)
36 }
37 None => (text, 0),
38 };
39 let (sign, mantissa) = mantissa
40 .strip_prefix('-')
41 .map_or(("", mantissa), |rest| ("-", rest));
42 let digits: Vec<char> = mantissa.chars().filter(|c| c.is_ascii_digit()).collect();
43 let before_dot = mantissa.find('.').unwrap_or(mantissa.len());
44 let point = before_dot as i32 + exponent;
45 let first_nonzero = digits
46 .iter()
47 .position(|c| *c != '0')
48 .unwrap_or(digits.len());
49 let mut digits = digits;
50 if digits.len() - first_nonzero > max_digits {
51 digits.truncate(first_nonzero + max_digits);
52 }
53 let mut out = String::from(sign);
54 if point <= 0 {
55 out.push_str("0.");
56 for _ in 0..(-point) {
57 out.push('0');
58 }
59 for c in &digits {
60 out.push(*c);
61 }
62 } else if point as usize >= digits.len() {
63 for c in &digits {
64 out.push(*c);
65 }
66 for _ in 0..(point as usize - digits.len()) {
67 out.push('0');
68 }
69 } else {
70 for (index, c) in digits.iter().enumerate() {
71 if index == point as usize {
72 out.push('.');
73 }
74 out.push(*c);
75 }
76 }
77 out
78}
79
80#[cfg(test)]
81mod tests {
82 use super::format_number;
83
84 #[test]
85 fn integers_print_without_decimals() {
86 assert_eq!(format_number(0.0), "0");
87 assert_eq!(format_number(100.0), "100");
88 assert_eq!(format_number(-3.0), "-3");
89 }
90
91 #[test]
92 fn floats_match_reference_precision() {
93 assert_eq!(format_number(1.8106601717798212), "1.810660171779821");
94 assert_eq!(format_number(-1.2803300858899105), "-1.280330085889910");
95 assert_eq!(format_number(0.016), "0.016");
96 assert_eq!(format_number(0.125), "0.125");
97 assert_eq!(format_number(1.5), "1.5");
98 }
99}