Why 1-0.4 = 0.6 vs 1 - 1.4 = -0.399999999999

why 1-0.4 = 0.6 vs 1 - 1.4 = -0.399999999999
and 0.1 - 0.5 = -0.4 vs 0.2 - 0.6 = -0.3999999

How to make the calculation consistent? What the best way to deal with that to be able to compare (0.2 - 0.6) == (0.1 - 0.5) to get true, not false as it is right now

Julia ver 1.11.5

Also PSA: floating-point arithmetic

5 Likes

Mose’s answer is what you need to read, but also just to directly answer your question

julia> (0.2 - 0.6) ≈ (0.1 - 0.5)
true

(that’s \approx<TAB>)

2 Likes

Oh, that question wasn’t there when I replied :sweat_smile:

1 Like

To build on previous answers: checking for precise equality in floating point math should be used in only specific situations and with an understanding of roundoff as you see it here. The issue is that the decimal system used by humans is not perfectly matchable by the base-2 floating point system most commonly used by computers. In particular, most numbers with a nice base-10 fractional part do not have a nice base-2 fractional so the result is rounded. You can use big (which uses more but ultimately still a finite number of base-2 bits) to get a little more info about the issue

julia> big(1.0) # this is exactly representable
1.0

julia> big(1.4) # closest available Float64 to 1.400000...
1.399999999999999911182158029987476766109466552734375

julia> big(1.0) - big(1.4)
-0.399999999999999911182158029987476766109466552734375

julia> Float64(big(1.0) - big(1.4)) # round the result to the closest Float64
-0.3999999999999999

Exact float arithmetic is not necessary in many situations. If you really need perfectly accurate base-10 arithmetic, I would suggest you try another approach such as Rational (although it is much slower and may overflow unless you use BigInt Rationals.)

julia> 1 - 14//10
-2//5

julia> Float64(1 - 14//10) # great! except...
-0.4

julia> big(Float64(1 - 14//10)) # -0.4 simply doesn't exist in binary floating point
-0.40000000000000002220446049250313080847263336181640625
2 Likes