Floating-point numbers in Rust are used to represent values with decimal parts and are fundamental for scientific computing and graphics processing. Rust provides two main floating-point types: f32 (single precision) and f64 (double precision), with f64 used by default to offer higher precision.

Floating-Point Types and Declaration

In Rust, floating-point numbers adhere to the IEEE 754 standard, supporting special values such as positive and negative infinity, NaN (Not a Number), etc. When declaring floating-point variables, you can use type annotations or let the compiler infer.

let x: f32 = 3.14; // single-precision floating-point number
let y = 2.718f64; // double-precision floating-point number, using suffix
println!("x = {}, y = {}", x, y);
// output: x = 3.14, y = 2.718

Handling Special Values

Floating-point numbers may produce NaN or infinity, which is important in error handling. Rust provides methods to check these values.

let nan = f64::NAN;
let inf = f64::INFINITY;
println!("is_nan: {}, is_infinite: {}", nan.is_nan(), inf.is_infinite());
// output: is_nan: true, is_infinite: true

Note: Direct comparison of NaN values returns false; you should use the is_nan() method. For example, nan == nan results in false.

Floating-Point Comparison

Due to limitations in binary representation, floating-point numbers may have precision errors, a common issue in any programming language:

fn main() {
    let x = 0.1_f64;
    let y = 0.2_f64;
    let z = x + y;
    
    println!("0.1 + 0.2 = {}", z);
    println!("Equal to 0.3? {}", z == 0.3);
    // output: 0.1 + 0.2 = 0.30000000000000004
    // Equal to 0.3? false
}

When comparing floating-point numbers, you should use tolerance-based comparison:

fn approx_equal(a: f64, b: f64, epsilon: f64) -> bool {
    (a - b).abs() < epsilon
}

fn main() {
    let result = 0.1 + 0.2;
    println!("{}", approx_equal(result, 0.3, 1e-10));  // true
}

Performance

f64 is generally slower than f32 but provides higher precision. In performance-critical applications, choose the type based on requirements. The following table compares the two types:

Type Precision Memory Usage
f32 Approximately 7 decimal digits 4 bytes
f64 Approximately 15 decimal digits 8 bytes