F32 printing options for accuracy?

I have the number 1255413760 which is exactly represented in an f32 but if i println it I get 1255413800. Anything I can do about that :)?
Funnily enough it does round trip back to 1255413760 since that is the closest.

#![feature(float_extras)]
#![allow(deprecated)]
use std::i64;

fn main(){
    let f: f32 = "1255413760".parse().unwrap();
    let (mantissa, exponent, sign) = f.integer_decode();
    let i = sign as i64 * (mantissa as i64) * i64::pow(2, exponent as u32);
    println!("m {} e {} s{}", mantissa, exponent, sign);
    println!("i {}", i);
    println!("f {}", f)
}

You can set the precision by {:.decimal_places}

println!("f {:.5}", f);

with this the output is:

m 9807920 e 7 s1
i 1255413760
f 1255413760.00000

Interesting. Wish it would print the right number without having to specify points though

1 Like

It's most likely a bug, as it prints the right number when parsed as f64 without formatting. I'm not sure where to file a bug but you should definitely open an issue.

(I've written the same response to #39428 just in case.)

This is intentional and is not an error (I've written the initial float-to-decimal routine). The point is that {} prints the closest decimal representation with the least significant digits that still round trips---having only 24 bits (7--8 decimal digits) of mantissa, this is expected. As you've discovered, giving the exact precision disables this behavior and prints the exact representation.

It might be argued that {} should behave just like {.0}. I personally disagree because the omission of useless digits is mandatory for more extreme cases:

  • 21023 = 89884656743115795386465259539451236680898848947115328636715040578866337902750481566354238661203768010560056939935696678829394884407208311246423715319737062188883946712432742638151109800623047059726541476042502884419075341171231440736956555270413618581675255342293149119973622969239858152417678164812112068608.
  • 2-1074 = 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625

For your information, {} will print the former as 898846567431158 followed by 293 zeroes, and the later as simply 0.0...05 with 323 zeroes after a decimal point, both are accurate and do not give the false sense of accuracy. Of course one can also argue that they should print in the scientific notation when placeholder zeroes starts to occur... Probably that should be another issue :slight_smile:

3 Likes