Conversion from f32 to i64

I'm converting a f32 to i64, but the resulting numbers are different.

fn main() {
    let x: f32 = 10000000000000.0;

    println!("{} {}", x, x as i64);
}

outputs

10000000000000 9999999827968

I know there are problems representing floats, but is this an expected behavior in rust? If yes, how can I work around it to get the same number?

Yes, this is an expected behavior in Rust. (Other languages behave the same.) There is no workaround: 10^13 is simply unrepresentable exactly with f32. (It is representable exactly with f64, however.)

3 Likes

Specifically, f32 has 24 bits of precision, so the number gets rounded when it's stored in f32:
10000000000000 = 0b10010001100001001110011100101010000000000000
9999999827968 = 0b10010001100001001110011100000000000000000000

When it's printed in decimal, 9999999827968 gets rounded again to 10000000000000, because it rounds to the "simplest" decimal number that has the same representation in f32.

Note that this will print the same output:

fn main() {
    let x: f32 = 9999999999999.0;

    println!("{} {}", x, x as i64);
}
10000000000000 9999999827968
1 Like

This is expected behaviour in IEEE 754, yes.

You might enjoy playing with https://evanw.github.io/float-toy/

You can see from tweaking bits there is that the next smaller float is 9,999,998,779,392 and the next bigger one is 10,000,000,876,544, so that 9,999,999,827,968 you saw is the closest representable value to 10¹³, and thus what you get.

2 Likes

Thanks!

I'm going to use f64 to "fix" the problem.

If your goal is to faithfully represent all i64 numbers, f64 is also not going to be sufficient, since f64 only has 53 bits of precision, not 64.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.