4
var num1 = 1.1
if num1 + 0.1 == 1.2 {print("true")} else {print("false")}

Result: false

var num1: Float = 1.1
if num1 + 0.1 == 1.2 {print("true")} else {print("false")}

Result: true

The former block of code has num1 which represents a double and the latter code block has num1 which represents a float.

My question: Why does the code with Float return true and the one with Double does not?

Bob Gilmore
  • 12,608
  • 13
  • 46
  • 53
THCoder
  • 142
  • 10
  • @Leo Dabus The one you suggested does not answer my question. I do know that it talks about the precision of floating-point number, but there is no part of the discussion that mentions why float returns true and double does not. So please consider again and remove the duplicate from my question. – THCoder Apr 05 '17 at 16:11
  • Float is single-precision and double is double-precision. – Leo Dabus Apr 05 '17 at 16:18
  • @Leo Dabus I think this is a valid question, i’m curious about the discrepancy between `Float` and `Double` too. If anything it should be the other way around… – taylor swift Apr 05 '17 at 16:18
  • @LeoDabus that doesn’t explain why the less precise format succeeds in the comparison, while the more precise format fails – taylor swift Apr 05 '17 at 16:19
  • Related http://stackoverflow.com/questions/588004/is-floating-point-math-broken – Ahmad F Apr 05 '17 at 16:23
  • 5
    It's not that interesting. It just accidentally rounded the right way. – harold Apr 05 '17 at 16:24
  • comparing floating point numbers with `==` is always a problem and should not be done at all. You are at the mercy of rounding errors. And as this example shows, it may well happen that it works for float but doesn't for double. – Henry Apr 05 '17 at 16:24
  • Add `print((num1 + 0.1).debugDescription, Double(1.2).debugDescription)` to the first case and `print((num1 + 0.1).debugDescription, Float(1.2).debugDescription)` to the second case. You'll see that none of the numbers is "correct". – Martin R Apr 05 '17 at 16:39

1 Answers1

3

This is a duplicate and I will close it as such, but here is an example of why this works for Float but not for Double.

Instead of looking at Double and Float, let's look at two new types. Eighths and Sixteenths. Eighths has 3 bits to represent fractional numbers, so you can represent 0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, and 0.875. Sixteenths has 4 bits to represent fractional numbers, so you can represent 0, 0.0625, 0.125, 0.1875, 0.25, and so on. In both number types, it will be necessary to approximate floating point values by choosing the closest value to the one you wish to represent.

So lets look at what 1.1 + 0.1 looks like in Eighths and Sixteenths.

Eighths

1.1 = 1.125
0.1 = 0.125
1.2 = 1.25

1.1 + 0.1 = 1.125 + 0.125 = 1.25

so 1.1 + 0.1 == 1.2 in Eighths

Sixteenths

1.1 = 1.125
0.1 = 0.125
1.2 = 1.1875

1.1 + 0.1 = 1.125 + 0.125 = 1.25

so 1.1 + 0.1 != 1.2 in Sixteenths.

The greater precision of Sixteenths makes it possible to more accurately represent 1.2 with a smaller value when represented in Sixteenths.

This is what is happening with Floats and Doubles. There are more bits available to represent the numbers, but they are still approximations. When you do math with those approximations, the error combines in unexpected ways which is why it is ill advised to be using equals comparisons with floating point values.

vacawama
  • 150,663
  • 30
  • 266
  • 294