[Python-ideas] Float range class

M.-A. Lemburg mal at egenix.com
Sat Jan 10 14:26:25 CET 2015

On 10.01.2015 11:47, Andrew Barnert wrote:
> On Jan 10, 2015, at 2:17, "M.-A. Lemburg" <mal at egenix.com> wrote:
>> Example:
>> naive_frange: [0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001,
>> 0.8, 0.9, 1.0]
>> frange: [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
> Your own example demonstrates that the naive version _doesn't_ accumulate error. Otherwise, 0.9 would be farther off than 0.7, and it's not.

You're right. The accumulation only happens when using a different
naive algorithm: one using addition for calculating the interval points.

def naive_add_frange(start, stop, steps):
    start = float(start)
    stop = float(stop)
    steps = int(steps)
    delta = (stop - start) / steps
    x = start
    for i in range(steps + 1):
        yield x
        x += delta

compared with the multiplication based naive algorithm (this is the
same as naive_frange used in the above example):

def naive_mul_frange(start, stop, steps):
    start = float(start)
    stop = float(stop)
    steps = int(steps)
    delta = (stop - start) / steps
    for i in range(steps + 1):
        yield start + i * delta

With multiplication, the relative errors of both arguments add up.
Since the relative errors of both arguments stay (mostly) the same,
there's no accumulation, unlike for the addition based variant,
where the error adds up in every step (and the relative error
can increase even more depending on the value of delta compared
to x).

Still I find the example results for frange() more in line with
what a user would expect.

Note: The frange() implementations include the right side of
the interval unlike range(). frange() steps refers to the number of
steps between the left and right side. Since the right side is included,
you get steps + 1 elements in the result.

Whether that's what a user would expect or not, is another discussion.

Here's the motivation for the frange() implementation:

A typical use case is creating values for an axis in a chart.
Say your axis goes from 0.0 to 1.0 and you want to split it up
in ten intervals, so you write frange(0.0, 1.0, 10).

PS: The type conversions in the example implementations are just
to signal which types I'm referring to. You can drop those and then
get all sorts of wonderful wanted and unwanted effects :-)

Marc-Andre Lemburg

Professional Python Services directly from the Source  (#1, Jan 10 2015)
>>> Python Projects, Coaching and Consulting ...  http://www.egenix.com/
>>> mxODBC Plone/Zope Database Adapter ...       http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/

::::: Try our mxODBC.Connect Python Database Interface for free ! ::::::

   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
           Registered at Amtsgericht Duesseldorf: HRB 46611

More information about the Python-ideas mailing list