<div dir="ltr">Your implementation of `fstride` is faulty, it doesn't produce the `through` value. Suggest you change to:<div><br></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(187,44,162)">public<span style="color:rgb(0,0,0)"> </span>extension<span style="color:rgb(0,0,0)"> </span><span style="color:rgb(112,61,170)">Double</span><span style="color:rgb(0,0,0)"> {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> <span style="color:rgb(187,44,162)">public</span> <span style="color:rgb(187,44,162)">func</span> doubleStride(through end: <span style="color:rgb(112,61,170)">Double</span>, by stride: <span style="color:rgb(112,61,170)">Double</span>) -> <span style="color:rgb(112,61,170)">LazyMapCollection</span><<span style="color:rgb(112,61,170)">Range</span><<span style="color:rgb(112,61,170)">Int</span>>, <span style="color:rgb(112,61,170)">Double</span>> {</p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> <span style="color:rgb(187,44,162)">let</span> limit = <span style="color:rgb(112,61,170)">Int</span>(<span style="color:rgb(61,29,129)">trunc</span>((end - <span style="color:rgb(187,44,162)">self</span>) / stride))</p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> <span style="color:rgb(187,44,162)">return</span> (<span style="color:rgb(39,42,216)">0</span> ... limit).<span style="color:rgb(112,61,170)">lazy</span>.<span style="color:rgb(61,29,129)">map</span> { <span style="color:rgb(187,44,162)">self</span> + <span style="color:rgb(112,61,170)">Double</span>($0) * stride }</p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> }</p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</p></div><div><br></div></div><div class="gmail_extra"><br clear="all"><div><div class="gmail_signature"> -- Howard.<br></div></div>
<br><div class="gmail_quote">On 1 March 2016 at 12:16, Erica Sadun via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><h1 style="font-size:2.25em;margin-right:0px;margin-bottom:16px;margin-left:0px;line-height:1.2;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255);margin-top:0px!important"><blockquote type="cite" style="font-family:Palatino;font-size:14px;font-weight:normal"><div style="word-wrap:break-word"><div><blockquote type="cite"><div>On Feb 29, 2016, at 5:03 PM, Joe Groff <<a href="mailto:jgroff@apple.com" target="_blank">jgroff@apple.com</a>> wrote:</div><div><div style="font-family:Palatino-Roman">I agree, splitting into two proposals is a good idea.</div><div style="font-family:Palatino-Roman"><br></div><div style="font-family:Palatino-Roman">-Joe</div></div></blockquote></div></div></blockquote></h1><h1 style="font-size:2.25em;margin-right:0px;margin-bottom:16px;margin-left:0px;line-height:1.2;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255);margin-top:0px!important">Decoupling Floating Point Strides from Generic Implementations</h1><ul style="padding:0px 0px 0px 2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>Proposal: SE-00XX</li><li>Author(s): <a href="http://github.com/erica" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">Erica Sadun</a></li><li>Status: TBD</li><li>Review manager: TBD</li></ul><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Swift strides create progressions along "notionally continuous one-dimensional values" using a series of offset values. This proposal replaces the Swift's generic stride implementation with seperate algorithms for integer strides (the current implementation) and floating point strides.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">This proposal was discussed on-list in the <a href="http://article.gmane.org/gmane.comp.lang.swift.evolution/8014" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">"[Discussion] stride behavior and a little bit of a call-back to digital numbers"</a>thread.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://gist.github.com/erica/cf50f3dc54bb3a090933#motivation" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Motivation</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Strideable</code> is genericized across both integer and floating point types. A single implementation causes floating point strides to accumulate errors through repeatedly adding <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">by</code> intervals. Floating point types deserve their own floating point-aware implementation that minimizes errors.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://gist.github.com/erica/cf50f3dc54bb3a090933#current-art" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Current Art</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">A <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Strideable to</code> sequence returns the sequence of values (<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">self</code>, <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">self + stride</code>, <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">self + stride + stride</code>, ... <em>last</em>) where <em>last</em> is the last value in the progression that is less than <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">end</code>.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">A <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Strideable through</code> sequence currently returns the sequence of values (<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">self</code>, <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">self + stride</code>, <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">self + tride + stride</code>, ... <em>last</em>) where <em>last</em> is the last value in the progression less than or equal to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">end</code>. There is no guarantee that <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">end</code> is an element of the sequence.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">While floating point calls present an extremely common use-case, they use integer-style math that accumulates errors during execution. Consider this example:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><pre style="overflow:auto;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;padding:16px;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-wrap:normal;word-break:normal"><span style="color:rgb(167,29,93)">let</span> ideal <span style="color:rgb(167,29,93)">=</span> [<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">2</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">3</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">4</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">5</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">6</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">7</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">8</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">9</span>, <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>]
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(0,134,179)">zip</span>(<span style="color:rgb(0,134,179)">Array</span>(<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">stride</span>(through: <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">01</span>, by: <span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>)), ideal)<span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">map</span>(<span style="color:rgb(167,29,93)">-</span>))
<span style="color:rgb(150,152,150)">// prints [0.0, 0.0, 2.2204460492503131e-16, 2.2204460492503131e-16, </span>
<span style="color:rgb(150,152,150)">// 4.4408920985006262e-16, 4.4408920985006262e-16, 4.4408920985006262e-16, </span>
<span style="color:rgb(150,152,150)">// 6.6613381477509392e-16, 6.6613381477509392e-16, 8.8817841970012523e-16, </span>
<span style="color:rgb(150,152,150)">// 8.8817841970012523e-16]</span></pre></div><ul style="padding:0px 0px 0px 2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>To create an array containing values from 1.0 to 2.0, the developer must add an epsilon value to the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">through</code>argument. Otherwise the stride progression ends near 1.9. Increasing the argument from <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">2.0</code> to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">2.01</code> is sufficient to include the end value.</li><li>The errors in the sequence increase over time. You see this as errors become larger towards the end of the progress. This is an artifact of the generic implementation.</li></ul><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://gist.github.com/erica/cf50f3dc54bb3a090933#detail-design" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Detail Design</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Under the current implementation, each floating point addition in a generic stride accrues errors. The following progression never reaches 2.0.</p><pre style="overflow:auto;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;margin-top:0px;margin-bottom:16px;line-height:1.45;padding:16px;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-wrap:normal;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;line-height:inherit;word-wrap:normal">print(Array(1.0.stride(through: 2.0, by: 0.1)))
// Prints [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9]
</code></pre><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">This same issue occurs with traditional C-style for loops. This is an artifact of floating point math, and not the specific Swift statements:</p><pre style="overflow:auto;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;margin-top:0px;margin-bottom:16px;line-height:1.45;padding:16px;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-wrap:normal;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;line-height:inherit;word-wrap:normal">var array: [Double] = []
for var i = 1.0; i <= 2.0; i += 0.1 {
array.append(i)
}
print("Array", array)
// Prints Array [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9]
</code></pre><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">You should not have to manually add an epsilon to force a progression to complete.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Floating point strides are inherently dissimilar to and should not be genericized with integer strides. I propose separate their implementation, freeing them to provide their own specialized progressions, using better numeric methods. In doing so, floating point values are no longer tied to implementations that unnecessarily accrue errors or otherwise provide less-than-ideal solutions.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">The following example provides a rough pass at what this might look like for floating point math. I leave specific algorithm details to experts; a decimal number solution would be more appropriate. The fun</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">See: <a href="https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">RandomAscii's write-ups on all things floating point</a>.</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><pre style="overflow:auto;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;padding:16px;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-wrap:normal;word-break:normal"><span style="color:rgb(167,29,93)">import</span> <span style="color:rgb(0,134,179)">Darwin</span>
<span style="color:rgb(150,152,150)">/// A `GeneratorType` for `DoubleStrideThrough`.</span>
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">struct</span> DoubleStrideThroughGenerator <span style="color:rgb(167,29,93)">:</span> <span style="color:rgb(0,134,179)">GeneratorType</span> {
<span style="color:rgb(167,29,93)">let</span> start: <span style="color:rgb(0,134,179)">Double</span>
<span style="color:rgb(167,29,93)">let</span> end: <span style="color:rgb(0,134,179)">Double</span>
<span style="color:rgb(167,29,93)">let</span> <span style="color:rgb(0,134,179)">stride</span>: <span style="color:rgb(0,134,179)">Double</span>
<span style="color:rgb(167,29,93)">var</span> iteration: <span style="color:rgb(0,134,179)">Int</span> <span style="color:rgb(167,29,93)">=</span> <span style="color:rgb(0,134,179)">0</span>
<span style="color:rgb(167,29,93)">var</span> done: <span style="color:rgb(0,134,179)">Bool</span> <span style="color:rgb(167,29,93)">=</span> <span style="color:rgb(0,134,179)">false</span>
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">init</span>(start: <span style="color:rgb(0,134,179)">Double</span>, end: <span style="color:rgb(0,134,179)">Double</span>, <span style="color:rgb(0,134,179)">stride</span>: <span style="color:rgb(0,134,179)">Double</span>) {
(<span style="color:rgb(167,29,93)">self</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">start</span>, <span style="color:rgb(167,29,93)">self</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">end</span>, <span style="color:rgb(167,29,93)">self</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">stride</span>) <span style="color:rgb(167,29,93)">=</span> (start, end, <span style="color:rgb(0,134,179)">stride</span>)
}
<span style="color:rgb(150,152,150)">/// Advance to the next element and return it, or `nil` if no next</span>
<span style="color:rgb(150,152,150)">/// element exists.</span>
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">mutating</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">next</span>() <span style="color:rgb(167,29,93)">-></span> <span style="color:rgb(0,134,179)">Double</span>? {
<span style="color:rgb(167,29,93)">if</span> done {
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">nil</span>
}
<span style="color:rgb(167,29,93)">let</span> current <span style="color:rgb(167,29,93)">=</span> start <span style="color:rgb(167,29,93)">+</span> <span style="color:rgb(0,134,179)">Double</span>(iteration) <span style="color:rgb(167,29,93)">*</span> <span style="color:rgb(0,134,179)">stride</span>; iteration <span style="color:rgb(167,29,93)">+=</span> <span style="color:rgb(0,134,179)">1</span>
<span style="color:rgb(167,29,93)">if</span> signbit(current <span style="color:rgb(167,29,93)">-</span> end) <span style="color:rgb(167,29,93)">==</span> signbit(<span style="color:rgb(0,134,179)">stride</span>) { <span style="color:rgb(150,152,150)">// thanks Joe Groff</span>
<span style="color:rgb(167,29,93)">if</span> <span style="color:rgb(0,134,179)">abs</span>(current) <span style="color:rgb(167,29,93)">></span> <span style="color:rgb(0,134,179)">abs</span>(end) {
done <span style="color:rgb(167,29,93)">=</span> <span style="color:rgb(0,134,179)">true</span>
<span style="color:rgb(167,29,93)">return</span> current
}
<span style="color:rgb(167,29,93)">return</span> <span style="color:rgb(0,134,179)">nil</span>
}
<span style="color:rgb(167,29,93)">return</span> current
}
}
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">struct</span> DoubleStrideThrough <span style="color:rgb(167,29,93)">:</span> <span style="color:rgb(0,134,179)">SequenceType</span> {
<span style="color:rgb(167,29,93)">let</span> start: <span style="color:rgb(0,134,179)">Double</span>
<span style="color:rgb(167,29,93)">let</span> end: <span style="color:rgb(0,134,179)">Double</span>
<span style="color:rgb(167,29,93)">let</span> <span style="color:rgb(0,134,179)">stride</span>: <span style="color:rgb(0,134,179)">Double</span>
<span style="color:rgb(150,152,150)">/// Return a *generator* over the elements of this *sequence*.</span>
<span style="color:rgb(150,152,150)">///</span>
<span style="color:rgb(150,152,150)">/// - Complexity: O(1).</span>
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">generate</span>() <span style="color:rgb(167,29,93)">-></span> DoubleStrideThroughGenerator {
<span style="color:rgb(167,29,93)">return</span> DoubleStrideThroughGenerator(
start: start, end: end, <span style="color:rgb(0,134,179)">stride</span>: <span style="color:rgb(0,134,179)">stride</span>)
}
<span style="color:rgb(167,29,93)">init</span>(start: <span style="color:rgb(0,134,179)">Double</span>, end: <span style="color:rgb(0,134,179)">Double</span>, <span style="color:rgb(0,134,179)">stride</span>: <span style="color:rgb(0,134,179)">Double</span>) {
_precondition(<span style="color:rgb(0,134,179)">stride</span> <span style="color:rgb(167,29,93)">!=</span> <span style="color:rgb(0,134,179)">0</span>, <span style="color:rgb(24,54,145)"><span>"</span>stride size must not be zero<span>"</span></span>)
(<span style="color:rgb(167,29,93)">self</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">start</span>, <span style="color:rgb(167,29,93)">self</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">end</span>, <span style="color:rgb(167,29,93)">self</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">stride</span>) <span style="color:rgb(167,29,93)">=</span> (start, end, <span style="color:rgb(0,134,179)">stride</span>)
}
}
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">extension</span> <span style="color:rgb(0,134,179)">Double</span> {
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">fstride</span>(
<span style="color:rgb(121,93,163)">through</span> <span>end</span>: <span style="color:rgb(0,134,179)">Double</span>, <span style="color:rgb(121,93,163)">by</span> <span>stride</span>: <span style="color:rgb(0,134,179)">Double</span>
) <span style="color:rgb(167,29,93)">-></span> DoubleStrideThrough {
<span style="color:rgb(167,29,93)">return</span> DoubleStrideThrough(
start: <span style="color:rgb(167,29,93)">self</span>, end: end, <span style="color:rgb(0,134,179)">stride</span>: <span style="color:rgb(0,134,179)">stride</span>)
}
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">This implementation reduces floating point error by limiting accumulated additions. It uses the current Swift 2.2 <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">through</code> semantics (versus the revised <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">through</code> semantics proposed under separate cover), so it never reaches 2.0 without adding an epsilon value.</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><pre style="overflow:auto;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;padding:16px;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-wrap:normal;word-break:normal"><span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(0,134,179)">Array</span>(<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span>fstride(through: <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, by: <span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>)))
<span style="color:rgb(150,152,150)">// prints [1.0, 1.1000000000000001, 1.2, 1.3, 1.3999999999999999,</span>
<span style="color:rgb(150,152,150)">// 1.5, 1.6000000000000001, 1.7000000000000002, 1.8, </span>
<span style="color:rgb(150,152,150)">// 1.8999999999999999]</span>
<span style="color:rgb(150,152,150)">// versus the old style</span>
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(0,134,179)">Array</span>(<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">stride</span>(through: <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, by: <span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>)))
<span style="color:rgb(150,152,150)">// prints [1.0, 1.1000000000000001, 1.2000000000000002, 1.3000000000000003, </span>
<span style="color:rgb(150,152,150)">// 1.4000000000000004, 1.5000000000000004, 1.6000000000000005, </span>
<span style="color:rgb(150,152,150)">// 1.7000000000000006, 1.8000000000000007, 1.9000000000000008]</span>
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(0,134,179)">zip</span>(<span style="color:rgb(0,134,179)">Array</span>(<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">stride</span>(through: <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, by: <span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>)),
<span style="color:rgb(0,134,179)">Array</span>(<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span>fstride(through: <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, by: <span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>)))<span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">map</span>(<span style="color:rgb(167,29,93)">-</span>))
<span style="color:rgb(150,152,150)">// prints [0.0, 0.0, 2.2204460492503131e-16, 2.2204460492503131e-16, </span>
<span style="color:rgb(150,152,150)">// 4.4408920985006262e-16, 4.4408920985006262e-16, 4.4408920985006262e-16, </span>
<span style="color:rgb(150,152,150)">// 4.4408920985006262e-16, 6.6613381477509392e-16, 8.8817841970012523e-16]</span>
<span style="color:rgb(167,29,93)">let</span> ideal <span style="color:rgb(167,29,93)">=</span> [<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">2</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">3</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">4</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">5</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">6</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">7</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">8</span>, <span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">9</span>]
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(0,134,179)">zip</span>(<span style="color:rgb(0,134,179)">Array</span>(<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span>fstride(through: <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, by: <span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>)), ideal)<span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">map</span>(<span style="color:rgb(167,29,93)">-</span>))
<span style="color:rgb(0,134,179)">print</span>(<span style="color:rgb(0,134,179)">zip</span>(<span style="color:rgb(0,134,179)">Array</span>(<span style="color:rgb(0,134,179)">1</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">stride</span>(through: <span style="color:rgb(0,134,179)">2</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">0</span>, by: <span style="color:rgb(0,134,179)">0</span><span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">1</span>)), ideal)<span style="color:rgb(167,29,93)">.</span><span style="color:rgb(0,134,179)">map</span>(<span style="color:rgb(167,29,93)">-</span>))
<span style="color:rgb(150,152,150)">// prints</span>
<span style="color:rgb(150,152,150)">// [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.2204460492503131e-16, 0.0, 0.0]</span>
<span style="color:rgb(150,152,150)">// [0.0, 0.0, 2.2204460492503131e-16, 2.2204460492503131e-16, </span>
<span style="color:rgb(150,152,150)">// 4.4408920985006262e-16, 4.4408920985006262e-16, 4.4408920985006262e-16, </span>
<span style="color:rgb(150,152,150)">// 6.6613381477509392e-16, 6.6613381477509392e-16, 8.8817841970012523e-16]</span></pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">If one were looking for a quick and dirty fix, the same kind of math used in this rough solution (<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">let value = start + count * interval</code>) could be adopted back into the current generic implementation.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://gist.github.com/erica/cf50f3dc54bb3a090933#alternatives-considered" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Alternatives Considered</h2><div style="margin-top:0px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255);margin-bottom:0px!important">While precision math for decimal numbers would be better addressed by introducing a decimal type and/or warnings for at-risk floating point numbers, those features lie outside the scope of this proposal.</div><div><br></div><br></div><br>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
<br></blockquote></div><br></div>