4

I ran into a strange problem, which I want to understand background of:

func printIntervals(_ colors: Int) {
    let start = 0.4 - (Double(colors) - 1) / 10
    print("start: \(start)")
    for i in stride(from: start, through: 0.4, by: 0.1) { print ("i:\(i)")}
}

printIntervals(1)
printIntervals(2)
printIntervals(3)
printIntervals(4)
printIntervals(5)
printIntervals(6)
printIntervals(7)
printIntervals(8)

Gives me this output:

colors: 1 start: 0.4
i:0.4
colors: 2 start: 0.3
i:0.3
i:0.4
colors: 3 start: 0.2
i:0.2
i:0.3
i:0.4
colors: 4 start: 0.1
i:0.1
i:0.2
i:0.3
colors: 5 start: 0.0
i:0.0
i:0.1
i:0.2
i:0.3
i:0.4
colors: 6 start: -0.1
i:-0.1
i:2.77555756156289e-17
i:0.1
i:0.2
i:0.3
i:0.4
colors: 7 start: -0.2
i:-0.2
i:-0.1
i:5.55111512312578e-17
i:0.1
i:0.2
i:0.3
colors: 8 start: -0.3
i:-0.3
i:-0.2
i:-0.0999999999999999
i:1.11022302462516e-16
i:0.1
i:0.2
i:0.3

As you can see, some function calls will include the 0.4 value an others won't... My quick workaround is to make the stride end at 0.41 instead, so it's definitely a precision issue.

But if the previous value is printed as 0.3 (not 0.300001), why would it skip 0.4 when incrementing by 0.1? And why does it only happen in some cases - but consistently?

Esben von Buchwald
  • 2,772
  • 1
  • 29
  • 37
  • As you said, this is due to floating point precision. Not every decimal value can be perfectly represented by a binary floating point value. And as a workaround I'd rather use `stride(from:to:by:)` with the limit that you don't want to reach instead of changing the limit of `stride(from:through:by)`, since as you experienced, in some cases the value cannot actually be reached. – Dávid Pásztor Aug 26 '17 at 23:30
  • 1
    Generally, it is better to use an integer to control loops, and multiply the iteration number by e.g. 0.1 at the start of each iteration. – Patricia Shanahan Aug 26 '17 at 23:47
  • 1
    Just use Decimal instead of Double. `Decimal(colors)` – Leo Dabus Aug 27 '17 at 01:02
  • Yeah, I found that it did actually start at -0.29999998 when I had 8 colors, which means that the 8th step would be at 0.4000002, which is above the limit. I'll try to use Double or stride to instead of through... Thanks guys – Esben von Buchwald Aug 27 '17 at 11:12

0 Answers0