talrost/
display.rs

1use std::num::FpCategory;
2
3/// Returns a specified-width string representation of the provided f64.
4/// The absolute minimum width is 3, but this may panic with overflow for widths
5/// under 7.
6#[allow(dead_code)]
7pub fn format_f64(n: f64, width: usize) -> String {
8    assert!(width >= 3);
9    let mut output = String::new();
10    let width_used: usize;
11
12    let class = n.classify();
13
14    if let FpCategory::Normal | FpCategory::Subnormal = class {
15        // TODO: Better handling of subnormal case
16
17        let mut formatting_width = 2;
18
19        let n_abs = n.abs();
20
21        if n_abs > n {
22            output.push('-');
23            formatting_width += 1;
24        }
25
26        let has_exponent: bool;
27        let exp_signed: isize = n_abs.abs().log10() as isize;
28        if exp_signed == 0 {
29            has_exponent = false;
30        } else {
31            has_exponent = true;
32            formatting_width += 1;
33            if exp_signed < 0 {
34                formatting_width += 1; // Exponent is negative, we'll need a '-'
35            }
36            let exp_wdh = 1 + (exp_signed as f64).abs().log10() as usize;
37            formatting_width += exp_wdh; // TODO: use int_log when stable
38        }
39
40        // TODO: Check trailing zeros and compact when possible
41        if !has_exponent {
42            output.push_str(&format!("{:.w$}", n_abs, w = width - formatting_width));
43        } else {
44            assert!(formatting_width <= width);
45            output.push_str(&format!("{:1.w$e}", n_abs, w = width - formatting_width));
46        }
47        width_used = width;
48    } else if let FpCategory::Zero = class {
49        // No distinction is made for negative zero
50        output.push_str("0.");
51        width_used = 2;
52    } else if let FpCategory::Infinite = class {
53        if n == f64::INFINITY {
54            output.push('∞');
55            width_used = 1;
56        } else {
57            output.push_str("-∞");
58            width_used = 2;
59        }
60    } else {
61        output.push_str("NaN");
62        width_used = 3;
63    }
64
65    let padding = width - width_used;
66    for _ in 0..padding {
67        output.push(' ');
68    }
69    output
70}