Comparison of two floats in Rust to arbitrary level of precision

From the Python documentation:

Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.

For more information, check out What Every Programmer Should Know About Floating-Point Arithmetic.


If you don't understand how computers treat floating points, don't use this code. If you know what trouble you are getting yourself into:

fn approx_equal(a: f64, b: f64, decimal_places: u8) -> bool {
    let factor = 10.0f64.powi(decimal_places as i32);
    let a = (a * factor).trunc();
    let b = (b * factor).trunc();
    a == b
}

fn main() {
    assert!( approx_equal(1.234, 1.235, 1));
    assert!( approx_equal(1.234, 1.235, 2));
    assert!(!approx_equal(1.234, 1.235, 3));
}

A non-exhaustive list of things that are known (or likely) to be broken with this code:

  • Sufficiently large floating point numbers and/or number of decimal points
  • Denormalized numbers
  • NaN
  • Infinities
  • Values near zero (approx_equal(0.09, -0.09, 1))

A potential alternative is to use either a fixed-point or arbitrary-precision type, either of which are going to be slower but more logically consistent to the majority of humans.


This one seems to work pretty well for me.

fn approx_equal (a: f64, b: f64, dp: u8) -> bool {
    let p = 10f64.powi(-(dp as i32));
    (a-b).abs() < p
}

Tags:

Rust