Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a compact but lossless string representation of a float in Rust?

Tags:

string

rust

As a variation of How can I convert a float to string?, I'm looking for a simple way to obtain a string representation of a float that is both concise and lossless. For instance:

let a = 1.0;
let b = 1.1234567890123456789012345678901e50;
let c = 1.1234567890123456789012345678901e-50;
for x in &[a, b, c] {
    println!("{}", x);
    println!("{:?}", x);
    println!("{}", x.to_string());
    println!("{}", f64::to_string(&x));
    println!("{:e}", x);
}

This produces:

1
1.0
1
1
1e0
112345678901234570000000000000000000000000000000000
112345678901234570000000000000000000000000000000000.0
112345678901234570000000000000000000000000000000000
112345678901234570000000000000000000000000000000000
1.1234567890123457e50
0.000000000000000000000000000000000000000000000000011234567890123456
0.000000000000000000000000000000000000000000000000011234567890123456
0.000000000000000000000000000000000000000000000000011234567890123456
0.000000000000000000000000000000000000000000000000011234567890123456
1.1234567890123456e-50

In other words:

  • {}, {:?}, x.to_string(), and f64::to_string(&x) all produce many leading/trailing zeros.
  • {:e} helps for printing b and c, but it enforces the exponential notation on all numbers, which results in unusual representations like 1e0.

Is there a way to produce a string that is lossless and uses exponential notation automatically only when it is appropriate?

Can such a conversion be extended generically to all numeric types?


To clarify the goal. I basically want the same how stringifying floats works in other programming language that smartly change from fixed point to exponential notation to produce an exact, human-readable representation. For instance on the JVM:

scala> (1.1234567890123456789012345678901e50).toString()
res1: String = 1.1234567890123457E50

scala> (1.0).toString()
res2: String = 1.0

scala> (1.1234567890123456789012345678901e-50).toString()
res3: String = 1.1234567890123456E-50
like image 548
bluenote10 Avatar asked Nov 20 '25 21:11

bluenote10


1 Answers

The requirement here is a little bit vague. You may want to try ryu crate to see if it fits your needs:

use ryu;  // ryu = "1.0"

fn main() {
    let mut buffer = ryu::Buffer::new();
    let a = 1.0;
    let b = 1.1234567890123456789012345678901e50;
    let c = 1.1234567890123456789012345678901e-50;
    for &x in [a, b, c].iter() {
        println!("{}", buffer.format(x));
    }
}

It produces the output:

1.0
1.1234567890123457e50
1.1234567890123456e-50
like image 144
edwardw Avatar answered Nov 24 '25 17:11

edwardw