<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Jan 9, 2015 at 2:06 PM, Andrew Barnert <span dir="ltr"><<a href="mailto:abarnert@yahoo.com.dmarc.invalid" target="_blank">abarnert@yahoo.com.dmarc.invalid</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div><div class="h5"><div>On Jan 9, 2015, at 13:24, Guido van Rossum <<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>> wrote:</div><div><br></div><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Jan 9, 2015 at 12:58 PM, Andrew Barnert <span dir="ltr"><<a href="mailto:abarnert@yahoo.com.dmarc.invalid" target="_blank">abarnert@yahoo.com.dmarc.invalid</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span>[...]</span><div>arange is actually very easy to get right, but hard to _use_ properly. A half-open range of values from 0 to .9 by .3 is going to include a number just under 0.9 if properly implemented. However you slice it, .3*3<.9, .3+.3+.3<.9, etc., so that number belongs in the range. [...]<br></div></div></blockquote><div><br></div><div>I don't know if this some kind of fp in-joke that I'm missing, but I find that the wording "if properly implemented" comes on a little strong. It depends on behavior of IEEE binary fp that's far from obvious -- I observe that .3*4 > 1.2, for example.</div></div></div></div></blockquote><div><br></div></div></div>OK, you're right; that isn't really stated well.<div><br></div><div>If properly implemented _with IEEE binary doubles_, .3*3 < .9. If properly implemented with a _different_ inexact float representation, that one might be fine--and a different one might be trouble.</div><div><br></div><div>But regardless, the mistake is not in the implementation of arange, it's in the user's assumption that .3*3 == .9 (or that 0+.3+.3+.3 == .9, or whatever, depending on how the stop was chosen). That may be true or false depending on your FP implementation, and therefore it's a bad assumption. And the fact that the == is inside your brain rather than in your code makes the red flag harder to spot.</div><div><br></div><div>Of course you can solve this the same way you solve any FP comparison issue: by picking an appropriate epsilon. For example, given that e << step, you can just count to .6+.15 or .9-.15 and be absolutely sure that something close to .6 will appear but something close to .9 will not. (And similarly for counting backward to 1.2 by .3.)<div><br></div><div>But rethinking your problem in terms of linspace is much harder to get wrong and requires much less understanding of how FP works.</div></div></div></blockquote></div><br></div><div class="gmail_extra">This is a beautiful illustration of how hard interface design is. Python's use of half-open intervals for range() works really well in combination with slicing (there's a Dijkstra note about this <a href="http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF">somewhere</a>). But extending it into the world of floating point, it suddenly becomes a liability, and the correct response is not to patch things up with epsilons but to redefine the interface to talk about dividing a given interval up in a given number of evenly-sized sub-intervals. (Although the actual signature of linspace gives me a headache. :-)<br clear="all"></div><div class="gmail_extra"><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido">python.org/~guido</a>)</div>
</div></div>