[swift-evolution] Feature proposal: Range operator with step

Stephen Canon scanon at apple.com
Thu Mar 31 13:29:35 CDT 2016


> On Mar 31, 2016, at 11:16 AM, Rainer Brockerhoff via swift-evolution <swift-evolution at swift.org> wrote:
> 
> On 3/31/16 15:06, Dave Abrahams via swift-evolution wrote:
>> 
>> on Thu Mar 31 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:
>> 
>>> Thoughts on an edge case: so long as it's possible to use
>>> `stride(from:to:by:)` with Double, we'll need to figure out what
>>> happens when you have `stride(from: 0.0, to: DBL_MAX, by: DBL_MIN)`.
>>> Bounds may be unknown at compile time, obviously.
>>> 
>>> Currently (this is by reasoning through the code, not actually
>>> observing it run), `for i in stride(from: 0.0, to: DBL_MAX, by:
>>> DBL_MIN) { }` degenerates into an infinite loop once you reach
>>> sufficient large values such that `current + stride == current`, which
>>> for a stride of DBL_MIN should happen pretty quickly.
>>> 
>>> In Erica's proposed floating point Stride, an Int is used to count
>>> iterations (and iterations need to be counted in order to avoid
>>> accumulating error). Thus, one must break from `for i in stride(from:
>>> 0.0, to: DBL_MAX, by: DBL_MIN) { }` before the iteration counter
>>> overflows or it will trap. IMO, trapping at some point is fine, but I
>>> think a limit of Int.max iterations might be rather arbitrary for a
>>> StrideTo<Double> (or whatever it will be named) and I'm not sure how
>>> one can justify why the behavior of StrideTo<Double> would change from
>>> machine to machine based on the size of Int.
>>> 
>>> I've been waffling between using an Int counter as Erica does or a
>>> counter of type Strideable.Stride in `StrideTo<Strideable where
>>> Strideable.Stride : FloatingPoint>`. In the latter alternative, no
>>> trapping occurs, but error begins to accumulate when the iteration
>>> counter is too large to represent integers exactly (e.g., 2^53 for
>>> Double). In that case, `for i in stride(from: 0.0, to: DBL_MAX, by:
>>> DBL_MIN) { }` degenerates into an infinite loop eventually (once
>>> `iterationCount + 1.0 == iterationCount`) and never traps, which I'm
>>> not sure I like, but a limit of 2^53 iterations bears at least a
>>> rational connection to Double and is known at compile time independent
>>> of the supplied bounds. We could alternatively return nil on reaching
>>> 2^53 iterations, trap, etc.
>>> 
>>> Comments?
>> 
>> I think I want to hear Steve Canon's input on this one.  I defer to him
>> on most things numeric.
> 
> In particular, should Steve confirm that the IEEE754 Decimal128 format
> is being worked on, and if simple decimal constants like those in
> 	`for i in stride(from: 0.0, to: DBL_MAX, by: DBL_MIN) { }`
> will be type-inferred as Decimal128, all that would "just work".

Decimal is something that I would like to see happen.  However, I would not expect any such proposal to result in that loop being type inferred to Decimal, since the to: and by: values are explicitly (binary floating-point) Doubles.

I also don’t think that such a loop is particularly useful.  For floating-point types, something like stride(from: T, to: T, steps: Int) seems safer and more workable to me (this is just my immediate reaction, I haven’t thought this through in detail, and am likely to change my mind if someone makes a good case).

– Steve


More information about the swift-evolution mailing list