1pub fn format_number(value: f64) -> String {
20 let abs = value.abs();
21
22 let (formatted, suffix) = if abs >= 1_000_000_000.0 {
24 (value / 1_000_000_000.0, "B")
25 } else if abs >= 1_000_000.0 {
26 (value / 1_000_000.0, "M")
27 } else if abs >= 1_000.0 {
28 (value / 1_000.0, "K")
29 } else {
30 (value, "")
31 };
32
33 if suffix.is_empty() {
35 if abs == 0.0 {
36 "0".to_string()
37 } else if abs < 0.01 {
38 format!("{:.4}", formatted)
39 } else if abs < 1.0 {
40 format!("{:.2}", formatted)
41 } else if formatted.fract() == 0.0 {
42 format!("{:.0}", formatted)
43 } else {
44 format!("{:.2}", formatted)
45 }
46 } else {
47 format!("{:.2}{}", formatted, suffix)
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn should_format_billions() {
57 assert_eq!(format_number(1_234_567_890.0), "1.23B");
58 assert_eq!(format_number(5_000_000_000.0), "5.00B");
59 }
60
61 #[test]
62 fn should_format_millions() {
63 assert_eq!(format_number(1_234_567.0), "1.23M");
64 assert_eq!(format_number(5_500_000.0), "5.50M");
65 }
66
67 #[test]
68 fn should_format_thousands() {
69 assert_eq!(format_number(1_234.0), "1.23K");
70 assert_eq!(format_number(52_647.0), "52.65K");
71 }
72
73 #[test]
74 fn should_format_whole_numbers() {
75 assert_eq!(format_number(42.0), "42");
76 assert_eq!(format_number(100.0), "100");
77 }
78
79 #[test]
80 fn should_format_decimals() {
81 assert_eq!(format_number(42.5), "42.50");
82 assert_eq!(format_number(0.75), "0.75");
83 }
84
85 #[test]
86 fn should_format_small_decimals() {
87 assert_eq!(format_number(0.005), "0.0050");
88 assert_eq!(format_number(0.0001), "0.0001");
89 }
90
91 #[test]
92 fn should_handle_zero() {
93 assert_eq!(format_number(0.0), "0");
94 }
95
96 #[test]
97 fn should_handle_negative_numbers() {
98 assert_eq!(format_number(-1_500.0), "-1.50K");
99 assert_eq!(format_number(-42.5), "-42.50");
100 }
101}