This means that someone forgot that 0.1 and 0.01 don't really exist in Rust (and most other contemporary languages).
Straight from Wikipedia: for example, the decimal number 0.1 is not representable in binary floating-point of any finite precision; the exact binary representation would have a "1100" sequence continuing endlessly.
Once you recall that and realize that “simple” examples which you are trying to use here are not simple at all… I guess you would be able to realize what's happening and why. Try to use numbers like 0.5 or 0.625 — these would be easier to reason about.
P.S. That's one reason which explains why COBOL is so hard to replace in banks. COBOL (unlike most modern languages) do have 0.1 and it works like you would expect. Most other languages (Rust including) only have approximations.
0.12 is converted to its closest f64, which is actually *exactly*
0.01 is converted to its closest f64, which is actually *exactly*
And thus the remainder is *exactly*
which Rust shows as
because that's enough to distinguish between the previous value
0.009999999999999992 which is sufficient to describe its exact value
and the next value
0.009999999999999995 which is sufficient to describe its exact value
Floating point numbers are an excellent solution to the whole "represent an infinite range of numbers using a finite number of bits" problem, but it's a leaky abstraction and sometimes you need to understand how they are implemented to know where those edge cases are.