How to use a decimal range() step value?

2018-12-31 03:56发布

Is there a way to step between 0 and 1 by 0.1?

I thought I could do it like the following, but it failed:

for i in range(0, 1, 0.1):
    print i

Instead, it says that the step argument cannot be zero, which I did not expect.

30条回答
无与为乐者.
2楼-- · 2018-12-31 04:44

To counter the float precision issues, you could use the Decimal module.

This demands an extra effort of converting to Decimal from int or float while writing the code, but you can instead pass str and modify the function if that sort of convenience is indeed necessary.

from decimal import Decimal
from decimal import Decimal as D


def decimal_range(*args):

    zero, one = Decimal('0'), Decimal('1')

    if len(args) == 1:
        start, stop, step = zero, args[0], one
    elif len(args) == 2:
        start, stop, step = args + (one,)
    elif len(args) == 3:
        start, stop, step = args
    else:
        raise ValueError('Expected 1 or 2 arguments, got %s' % len(args))

    if not all([type(arg) == Decimal for arg in (start, stop, step)]):
        raise ValueError('Arguments must be passed as <type: Decimal>')

    # neglect bad cases
    if (start == stop) or (start > stop and step >= zero) or \
                          (start < stop and step <= zero):
        return []

    current = start
    while abs(current) < abs(stop):
        yield current
        current += step

Sample outputs -

list(decimal_range(D('2')))
# [Decimal('0'), Decimal('1')]
list(decimal_range(D('2'), D('4.5')))
# [Decimal('2'), Decimal('3'), Decimal('4')]
list(decimal_range(D('2'), D('4.5'), D('0.5')))
# [Decimal('2'), Decimal('2.5'), Decimal('3.0'), Decimal('3.5'), Decimal('4.0')]
list(decimal_range(D('2'), D('4.5'), D('-0.5')))
# []
list(decimal_range(D('2'), D('-4.5'), D('-0.5')))
# [Decimal('2'),
#  Decimal('1.5'),
#  Decimal('1.0'),
#  Decimal('0.5'),
#  Decimal('0.0'),
#  Decimal('-0.5'),
#  Decimal('-1.0'),
#  Decimal('-1.5'),
#  Decimal('-2.0'),
#  Decimal('-2.5'),
#  Decimal('-3.0'),
#  Decimal('-3.5'),
#  Decimal('-4.0')]
查看更多
不再属于我。
3楼-- · 2018-12-31 04:45

And if you do this often, you might want to save the generated list r

r=map(lambda x: x/10.0,range(0,10))
for i in r:
    print i
查看更多
只靠听说
4楼-- · 2018-12-31 04:45

The trick to avoid round-off problem is to use a separate number to move through the range, that starts and half the step ahead of start.

# floating point range
def frange(a, b, stp=1.0):
  i = a+stp/2.0
  while i<b:
    yield a
    a += stp
    i += stp

Alternatively, numpy.arange can be used.

查看更多
余生请多指教
5楼-- · 2018-12-31 04:46

Add auto-correction for the possibility of an incorrect sign on step:

def frange(start,step,stop):
    step *= 2*((stop>start)^(step<0))-1
    return [start+i*step for i in range(int((stop-start)/step))]
查看更多
孤独寂梦人
6楼-- · 2018-12-31 04:47

frange(start, stop, precision)

def frange(a,b,i):
    p = 10**i
    sr = a*p
    er = (b*p) + 1
    p = float(p)
    return map(lambda x: x/p, xrange(sr,er))

In >frange(-1,1,1)

Out>[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
查看更多
永恒的永恒
7楼-- · 2018-12-31 04:47

Increase the magnitude of i for the loop and then reduce it when you need it.

for i * 100 in range(0, 100, 10):
    print i / 100.0

EDIT: I honestly cannot remember why I thought that would work syntactically

for i in range(0, 11, 1):
    print i / 10.0

That should have the desired output.

查看更多
登录 后发表回答