rust/tests/ui/float_cmp.rs
Sander Saares a067cd24ac Replace incorrect suggested fix for float_cmp
Using `f32::EPSILON` or `f64::EPSILON` as the floating-point equality comparison error margin is incorrect, yet `float_cmp` has until now recommended this be done. This change fixes the given guidance (both in docs and compiler hints) to not reference these unsuitable constants.

Instead, the guidance now clarifies that the scenarios in which an absolute error margin is usable, provides a reference implementation of using a user-defined absolute error margin (as an absolute error margin can only be used-defined and may be different for different comparisons) and references the floating point guide for a reference implementation of relative error based equaltiy comparison for when absolute error margin cannot be used.

changelog: Fix guidance of [`float_cmp`] and [`float_cmp_const`] to not incorrectly recommend `f64::EPSILON` as the error margin.

Fixes #6816
2024-07-09 10:12:09 +03:00

137 lines
3.4 KiB
Rust

// FIXME(f16_f128): const casting is not yet supported for these types. Add when available.
#![warn(clippy::float_cmp)]
#![allow(
unused,
clippy::no_effect,
clippy::op_ref,
clippy::unnecessary_operation,
clippy::cast_lossless
)]
//@no-rustfix
use std::ops::Add;
const ZERO: f32 = 0.0;
const ONE: f32 = ZERO + 1.0;
fn twice<T>(x: T) -> T
where
T: Add<T, Output = T> + Copy,
{
x + x
}
fn eq_fl(x: f32, y: f32) -> bool {
if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn
}
fn fl_eq(x: f32, y: f32) -> bool {
if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn
}
struct X {
val: f32,
}
impl PartialEq for X {
fn eq(&self, o: &X) -> bool {
if self.val.is_nan() {
o.val.is_nan()
} else {
self.val == o.val // no error, inside "eq" fn
}
}
}
impl PartialEq<f32> for X {
fn eq(&self, o: &f32) -> bool {
if self.val.is_nan() {
o.is_nan()
} else {
self.val == *o // no error, inside "eq" fn
}
}
}
fn main() {
ZERO == 0f32; //no error, comparison with zero is ok
1.0f32 != f32::INFINITY; // also comparison with infinity
1.0f32 != f32::NEG_INFINITY; // and negative infinity
ZERO == 0.0; //no error, comparison with zero is ok
ZERO + ZERO != 1.0; //no error, comparison with zero is ok
let x = X { val: 1.0 };
x == 1.0; // no error, custom type that implement PartialOrder for float is not checked
ONE == 1f32;
ONE == 1.0 + 0.0;
ONE + ONE == ZERO + ONE + ONE;
ONE != 2.0;
ONE != 0.0; // no error, comparison with zero is ok
twice(ONE) != ONE;
ONE as f64 != 2.0;
//~^ ERROR: strict comparison of `f32` or `f64`
ONE as f64 != 0.0; // no error, comparison with zero is ok
let x: f64 = 1.0;
x == 1.0;
//~^ ERROR: strict comparison of `f32` or `f64`
x != 0f64; // no error, comparison with zero is ok
twice(x) != twice(ONE as f64);
//~^ ERROR: strict comparison of `f32` or `f64`
x < 0.0; // no errors, lower or greater comparisons need no fuzzyness
x > 0.0;
x <= 0.0;
x >= 0.0;
let xs: [f32; 1] = [0.0];
let a: *const f32 = xs.as_ptr();
let b: *const f32 = xs.as_ptr();
assert_eq!(a, b); // no errors
const ZERO_ARRAY: [f32; 2] = [0.0, 0.0];
const NON_ZERO_ARRAY: [f32; 2] = [0.0, 0.1];
let i = 0;
let j = 1;
ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i
NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
//~^ ERROR: strict comparison of `f32` or `f64`
let a1: [f32; 1] = [0.0];
let a2: [f32; 1] = [1.1];
a1 == a2;
//~^ ERROR: strict comparison of `f32` or `f64` arrays
a1[0] == a2[0];
//~^ ERROR: strict comparison of `f32` or `f64`
// no errors - comparing signums is ok
let x32 = 3.21f32;
1.23f32.signum() == x32.signum();
1.23f32.signum() == -(x32.signum());
1.23f32.signum() == 3.21f32.signum();
1.23f32.signum() != x32.signum();
1.23f32.signum() != -(x32.signum());
1.23f32.signum() != 3.21f32.signum();
let x64 = 3.21f64;
1.23f64.signum() == x64.signum();
1.23f64.signum() == -(x64.signum());
1.23f64.signum() == 3.21f64.signum();
1.23f64.signum() != x64.signum();
1.23f64.signum() != -(x64.signum());
1.23f64.signum() != 3.21f64.signum();
// the comparison should also look through references
&0.0 == &ZERO;
&&&&0.0 == &&&&ZERO;
}