1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
#![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`
//~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
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`
//~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
x != 0f64; // no error, comparison with zero is ok
twice(x) != twice(ONE as f64);
//~^ ERROR: strict comparison of `f32` or `f64`
//~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
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`
//~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
let a1: [f32; 1] = [0.0];
let a2: [f32; 1] = [1.1];
a1 == a2;
//~^ ERROR: strict comparison of `f32` or `f64` arrays
//~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
a1[0] == a2[0];
//~^ ERROR: strict comparison of `f32` or `f64`
//~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
// 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;
}
|