Bug in f64 when given a large integer within precision?

the following:

use assert_float_eq::*;

fn main() {
    const A: f64 = 98148824396622615.;
    const B: f64 = 98148824396622610.;
    println!("{A}");
    assert_float_absolute_eq!(A, B, f64::EPSILON);
    println!("{}", A - B);
}

i am getting this:

98148824396622610
0

...which seems incorrect. Given that floats are fuzzy, is this in fact a bug?

FWIW I consistently obtain the correct answer in a different language, and it mattered for the problem I was tackling.

The values of A and B will be rounded off to the nearest representable f64 value, which happen to be the same. A - B will evaluate to 0 and your assertion will succeed (when it shouldn't).

If this kind of exact arithmetic is important to you, perhaps a crate like rust_decimal would be a better fit.

For example:

use rust_decimal::Decimal;
use rust_decimal_macros::dec;

fn main() {
    let A: Decimal = dec!(98148824396622615.0);
    let B: Decimal = dec!(98148824396622610.0);
    println!("{A}");
    assert_eq!(A - B, dec!(5)); // OK
    println!("{}", A - B);
}

and the output is

98148824396622615.0
5.0
3 Likes

Concretely, the largest integer value you can store in f64, without an omitted integer value below it, is 253 = 9,007,199,254,740,991.0. That's a tenth of your numbers.

6 Likes

And the two closest representable values are

98148824396622608.0
98148824396622624.0

And both your values are close to the former than the latter.

1 Like

Thank you to all! My question was

Given that floats are fuzzy, is this in fact a bug?

...and while I don't see an explicit answer, it seems the answer is "no". I especially appreciate the pointer to rust_decimal, and suspect its implementation is similar to that of the other language I was looking at.

64 bit floating point numbers has 53 mantissa bits, which determines the precision.

you can go to this website and put the number in to see the actual bit pattern:

https://bartaz.github.io/ieee754-visualization/

3 Likes

https://float.exposed/ is another float exploration website, among many more I'm sure.

2 Likes

I agree that the answer is "no". All the standard numeric types in Rust are clearly marked as limited-precision (e.g. the 64 in f64), and the two numbers A and B are not exactly representable as f64 values, so erroneous results from calculations are only to be expected. Other replies have given useful details about how this loss of precision works.

The numeric types in rust_decimal and similar crates are also of limited precision, but you can probably use them for a lot longer before running into errors, at the cost of (slightly) more memory usage and computation time.

1 Like

To follow up: I was able to use them longer before running into errors... but run into errors I did. :sob:

thread 'main' panicked at /home/me/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rust_decimal-1.36.0/src/arithmetic_impls.rs:232:18:
Multiplication overflowed

I do get it to work with f128, but that's unstable. I'll look at this more, thanks.

Try bigdecimal or dashu?

https://crates.io/crates/bigdecimal

I managed to make rust_decimal work. The problem turned out to be the well-known issue of instability when pivoting a matrix. Delicate handling very small absolute values solved the problem.

Were I to think more carefully about what I am doing, I might could remove the guard, but I am not sure about that.

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.