How do you format a float to the first significant decimal and with specified precision

Viewed 1356

I'm new to Rust (and coming from a Javascript background), so I decided to build a number formatting application to learn more about it.

One function in the application can accept a tiny float (e.g. 0.000435), and a precision value (e.g. 2), and should return the float formatted to the first significant decimal and with the specified precision applied (e.g. 0.00044)

For example, the function should accept and return the following:

  fn meh(float: f64, precision: usize) -> String {
    // ... magic happens ... format!(...
  }

  let float = 0.000456;
  let precision = 2:
  let result_a = meh(float, precision);
  // result_a => "0.00046"

  let float = 0.043256;
  let precision = 3:
  let result_b = meh(float, precision);
  // result_b => "0.0433"

I know that format! helps with precision. But I can't find a decent way to find the first significant decimal with out doing something funny like "convert float to a String and iterate until a non-zero value is found...."

I hope that makes sense, any help would be most appreciated.

1 Answers

As mentioned in the comments, Rust's interpretation of "precision" is "number of digits after the decimal point". However, if we instead want it to mean "number of significant digits", we can write the meh function to take this into account:

fn meh(float: f64, precision: usize) -> String {
    // compute absolute value
    let a = float.abs();

    // if abs value is greater than 1, then precision becomes less than "standard"
    let precision = if a >= 1. {
        // reduce by number of digits, minimum 0
        let n = (1. + a.log10().floor()) as usize;
        if n <= precision {
            precision - n
        } else {
            0
        }
    // if precision is less than 1 (but non-zero), then precision becomes greater than "standard"
    } else if a > 0. {
        // increase number of digits
        let n = -(1. + a.log10().floor()) as usize;
        precision + n
    // special case for 0
    } else {
        0
    };

    // format with the given computed precision
    format!("{0:.1$}", float, precision)
}

Playground example with test cases

Related