Also:

No; the issue affects (almost) all decimals, but the way that they’re rounded for display happens to hide the problem in the other cases you’ve tried.

As mentioned above, floating-point numbers are stored as *binary* floating point (with an integer mantissa, and an integer number of powers of two by which to multiple or divide it). Just as 1/3 can’t be represented exactly as a decimal fraction (0.33333…), so 1/10 doesn’t fit into a binary fraction (0.0001100110011…). So what you start from isn’t 1.23 and 1.20, but a pair of binary floating-point numbers that are very *close* to 1.23 and 1.20. Ditto their sum.

When you print floating-point numbers out, it picks the nearest decimal fraction — and in many cases, those approximations cancel out. But not always, as you’ve found!

**If you want exact results, don’t use floating-point.** BigDecimal is far better. (Or, if you need fixed precision, you could multiply all your numbers by that factor and store then as ints. Or some other approach. But BigDecimals are the usual solution — especially in Kotlin, where they’re so easier to use!)