The confusion is over examples like this:
fn main() {
let x: f64 = 0.1;
let y: f64 = 0.2;
let z: f64 = 0.3;
println!("x = {x}");
println!("y = {y}");
println!("z = {z}");
println!("x + y == z: {}", x+y == z);
}
where one might expect the last line to print true
, but it prints false
:
x = 0.1
y = 0.2
z = 0.3
x + y == z: false
Increasing the number of digits to twenty makes it more clear what is going on:
x = 0.10000000000000000555
y = 0.20000000000000001110
z = 0.29999999999999998890
x + y == z: false
But the values printed are not exactly representing the actual values stored. To get the exact values, we need 54-55 digits:
x = 0.1000000000000000055511151231257827021181583404541015625
y = 0.200000000000000011102230246251565404236316680908203125
z = 0.299999999999999988897769753748434595763683319091796875
x + y == z: false
Considering that only the first 16 digits still represent the intended value, 54 digits seems like a lot.
A user might be doing:
let pi: f64 = 3.1415926535897932384626433;
where the exact value will be:
3.141592653589793115997963468544185161590576171875
A user may or may not notice that something has changed.
(at least, Clippy will warn of "excessive precision" and suggest to remove everything after 793)
Making it easier to debug floats may help, but really, we want to warn users that anyone who wants to use floats should understand certain basics.
Using ==
or !=
on floats is almost always a mistake, I think there should be a Clippy rule about it.
(The only valid use case for ==
/!=
on floats I know of is writing a JavaScript engine, where floats are used as an integer substitute.)