# [Python-ideas] Float range class

Guido van Rossum guido at python.org
Fri Jan 9 23:36:59 CET 2015

```On Fri, Jan 9, 2015 at 2:06 PM, Andrew Barnert <
abarnert at yahoo.com.dmarc.invalid> wrote:

> On Jan 9, 2015, at 13:24, Guido van Rossum <guido at python.org> wrote:
>
> On Fri, Jan 9, 2015 at 12:58 PM, Andrew Barnert <
> abarnert at yahoo.com.dmarc.invalid> wrote:
>
>> [...]
>> 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. [...]
>>
>
> 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.
>
>
> OK, you're right; that isn't really stated well.
>
> 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.
>
> 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
> assumption. And the fact that the == is inside your brain rather than in
> your code makes the red flag harder to spot.
>
> 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.)
>
> But rethinking your problem in terms of linspace is much harder to get
> wrong and requires much less understanding of how FP works.
>

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
<http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF>). 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