As you know most decimal numbers can't be stored exactly. That's true for all of your above numbers except 1.0
.
But they get stored with a high accuracy. Instead of 0.3
, some very close representable number gets used. It's not only very close, it's the closest such number.
When you compute 0.1 + 0.2
, then another representable number gets computed, which is also very close to 0.3
. You are "unlucky" and it differs from the closest possible representable number.
There's no real luck involved, both 0.1
and 0.2
get represented by a slightly larger number. When added, the two errors add as they're of the same sign and you get something like 0.30000000000000004
.
With 0.45 + 0.55
, the errors are of different signs and cancel out.