Generating equally-spaced floats with least rounding error

Stefan Krah stefan-usenet at bytereef.org
Sat Sep 24 16:30:45 EDT 2011


Arnaud Delobelle <arnodel at gmail.com> wrote:
> >>>> start, stop, n = -1, 1.1, 7
> >>>> [float(F(start) + i*(F(stop)-F(start))/n) for i in range(n+1)]
> > [-1.0, -0.7, -0.39999999999999997, -0.09999999999999996,
> > 0.20000000000000004, 0.5000000000000001, 0.8, 1.1]
> 
> >>> start, stop, n = -1, 1.1, 7
> >>> [((n-i)*start + i*stop)/n for i in range(n+1)]
> [-1.0, -0.7000000000000001, -0.39999999999999997,
> -0.09999999999999996, 0.20000000000000004, 0.5, 0.8, 1.1]
> 
> On these examples, using fractions is no better than what I suggested
> in my previous post.

Why not use Decimal if one needs exact endpoints? Something like:

def drange(start, stop, step=1):
    if (step == 0):
        raise ValueError("step must be != 0")
    with localcontext() as ctx:
        ctx.traps[Inexact] = True
        x = start
        cmp = -1 if step > 0 else 1
        while x.compare(stop) == cmp:
            yield float(x)
            x += step


>>> list(drange(Decimal(1), Decimal("3.1"), Decimal("0.3")))
[1.0, 1.3, 1.6, 1.9, 2.2, 2.5, 2.8]
>>> list(drange(Decimal(-1), Decimal("1.1"), Decimal("0.3")))
[-1.0, -0.7, -0.4, -0.1, 0.2, 0.5, 0.8]
>>> list(drange(Decimal(-1), Decimal("1.1"), Decimal("0.1823612873")))
[-1.0, -0.8176387127, -0.6352774254, -0.4529161381, -0.2705548508, -0.0881935635, 0.0941677238, 0.2765290111, 0.4588902984, 0.6412515857, 0.823612873, 1.0059741603]
>>> list(drange(Decimal(-1), Decimal("1.1"), Decimal(1)/3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in drange
  File "/usr/lib/python3.2/decimal.py", line 1178, in __add__
    ans = ans._fix(context)
  File "/usr/lib/python3.2/decimal.py", line 1652, in _fix
    context._raise_error(Inexact)
  File "/usr/lib/python3.2/decimal.py", line 3836, in _raise_error
    raise error(explanation)
decimal.Inexact: None



Stefan Krah





More information about the Python-list mailing list