浮点数的range()


140

range()Python中的浮点数是否等效?

>>> range(0.5,5,1.5)
[0, 1, 2, 3, 4]
>>> range(0.5,5,0.5)

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    range(0.5,5,0.5)
ValueError: range() step argument must not be zero

1
这些不是分数,而是浮点数。浮点数...好吧,可能会得出与您预期不同的结果。

6
一个快速的解决方法是治疗整数为小数,如:range(5, 50, 5),然后只需10分每一个数字
NullUserException

@delnan-更新。我愿意接受微小的误差以方便浮动范围
乔纳森(Jonathan)


@NullUserException-这只是一个例子-实际代码当然是参数化的:)
Jonathan

Answers:


97

我不知道一个内置的功能,但是写一个像这样应该不会太复杂。

def frange(x, y, jump):
  while x < y:
    yield x
    x += jump

如评论所述,这可能会产生不可预测的结果,例如:

>>> list(frange(0, 100, 0.1))[-1]
99.9999999999986

为了获得预期的结果,您可以使用此问题中的其他答案之一,或者如@Tadhg所述,可以将其decimal.Decimal用作jump参数。确保使用字符串而不是浮点数对其进行初始化。

>>> import decimal
>>> list(frange(0, 100, decimal.Decimal('0.1')))[-1]
Decimal('99.9')

甚至:

import decimal

def drange(x, y, jump):
  while x < y:
    yield float(x)
    x += decimal.Decimal(jump)

然后:

>>> list(drange(0, 100, '0.1'))[-1]
99.9

34
Python的座右铭实际上是应该有一种-最好只有一种-显而易见的方法。但是Python仍然很棒:)
乔纳森(Jonathan)

3
>>> print list(frange(0,100,0.1))[-1]==100.0将是False
Volodimir Kopey 2015年

frange会意外地工作。由于浮点运算诅咒,例如frange(0.0, 1.0, 0.1)产生11个值,最后一个值是0.9999999999999999。实际的改进是,while x + sys.float_info.epsilon < y:尽管即使这样做也可能会因大量失败而失败
AkseliPalén16年

10
-1 请不要使用此代码,至少不要在可能影响我生活的软件中使用。没有办法使其可靠地工作。也不要使用AkseliPalén的答案。使用Xaerxess或wim的答案(除非忽略有关arange的部分)。
benrg '16

3
如果您将其decimal.Decimal用作步数而不是浮点数,效果很好。
塔德格·麦克唐纳

112

您可以使用:

[x / 10.0 for x in range(5, 50, 15)]

或使用lambda / map:

map(lambda x: x/10.0, range(5, 50, 15))

1
和array(range(5,50,15))/ 10.0作为numpy数组具有用于处理除法,乘法等操作符
edvaldig 2011年

2
@edvaldig:您是对的,我对此一无所知。尽管如此,我认为arange(0.5, 5, 1.5)IMO更具可读性。
Xaerxess 2011年

2
我更喜欢这个答案,而不是公认的答案,因为提出的前两个解决方案是基于对整数进行迭代并从整数中得出最终的浮点数。这更加健壮。如果直接使用浮点数进行操作,则由于在内部表示浮点数,您可能会遇到奇怪的一次性错误。例如,如果尝试list(frange(0, 1, 0.5)),它可以正常工作,并且排除1,但是如果尝试list(frange(0, 1, 0.1)),则得到的最后一个值接近1.0,这可能不是您想要的。这里介绍的解决方案没有这个问题。
blubberdiblub 2015年

3
切勿使用numpy.arange(numpy文档本身建议不要这样做)。使用wim推荐的numpy.linspace或此答案中的其他建议之一。
benrg '16

79

我曾经使用过,numpy.arange但是由于浮点错误,控制返回的元素数量有些复杂。所以现在我使用linspace,例如:

>>> import numpy
>>> numpy.linspace(0, 10, num=4)
array([  0.        ,   3.33333333,   6.66666667,  10.        ])

尽管仍未使用,但仍然存在浮点错误decimal,例如:np.linspace(-.1,10,num=5050)[0]
TNT

2
@TNT不,这不是错误。你会发现np.linspace(-.1,10,num=5050)[0] == -.1是真的。只是repr(np.float64('-0.1'))显示的数字更多。
wim

1
尽管该特定示例未显示出过多的舍入误差,但仍存在故障情况。例如,在理想结果print(numpy.linspace(0, 3, 148)[49])为时打印。比做的要好得多,但不能保证产生尽可能小的舍入误差。0.99999999999999991.0linspacearange
user2357112支持Monica

保证执行正确的端点处理,并总是产生完全相同元素的请求数量。
user2357112支持Monica

40

Pylab具有frange(实际上是的包装器matplotlib.mlab.frange):

>>> import pylab as pl
>>> pl.frange(0.5,5,0.5)
array([ 0.5,  1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5,  5. ])

4
从matplotlib 2.2版开始,不再推荐使用Frange。应该使用numpy.arange。
kuzavas

13

经过认真评估(2.x range):

[x * .5 for x in range(10)]

懒惰地评估(2.x xrange,3.x range):

itertools.imap(lambda x: x * .5, xrange(10)) # or range(10) as appropriate

交替:

itertools.islice(itertools.imap(lambda x: x * .5, itertools.count()), 10)
# without applying the `islice`, we get an infinite stream of half-integers.

4
+1; 但是为什么不(x * .5 for x in range(10))作为生成器表达式进行惰性求值呢?
蒂姆·皮茨克

2
因为那太容易了,我猜呢?:)
Karl Knechtel'9

11

使用itertools:延迟评估浮点范围:

>>> from itertools import count, takewhile
>>> def frange(start, stop, step):
        return takewhile(lambda x: x< stop, count(start, step))

>>> list(frange(0.5, 5, 1.5))
# [0.5, 2.0, 3.5]

3
+1以使用itertools.takewhile。但是,存在itertools.count(start, step)累积的浮点误差。(takewhile(lambda x: x < 100, count(0, 0.1))例如,评估。)我会写takewhile(lambda x: x < stop, (start + i * step for i in count()))
musiphil

6

我帮助将函数numeric_range添加到包more-itertools中

more_itertools.numeric_range(start, stop, step) 行为类似于内置函数范围,但可以处理浮点数,小数和小数类型。

>>> from more_itertools import numeric_range
>>> tuple(numeric_range(.1, 5, 1))
(0.1, 1.1, 2.1, 3.1, 4.1)

4

没有这样的内置函数,但是您可以使用以下代码(Python 3代码)来完成Python所允许的安全工作。

from fractions import Fraction

def frange(start, stop, jump, end=False, via_str=False):
    """
    Equivalent of Python 3 range for decimal numbers.

    Notice that, because of arithmetic errors, it is safest to
    pass the arguments as strings, so they can be interpreted to exact fractions.

    >>> assert Fraction('1.1') - Fraction(11, 10) == 0.0
    >>> assert Fraction( 0.1 ) - Fraction(1, 10) == Fraction(1, 180143985094819840)

    Parameter `via_str` can be set to True to transform inputs in strings and then to fractions.
    When inputs are all non-periodic (in base 10), even if decimal, this method is safe as long
    as approximation happens beyond the decimal digits that Python uses for printing.


    For example, in the case of 0.1, this is the case:

    >>> assert str(0.1) == '0.1'
    >>> assert '%.50f' % 0.1 == '0.10000000000000000555111512312578270211815834045410'


    If you are not sure whether your decimal inputs all have this property, you are better off
    passing them as strings. String representations can be in integer, decimal, exponential or
    even fraction notation.

    >>> assert list(frange(1, 100.0, '0.1', end=True))[-1] == 100.0
    >>> assert list(frange(1.0, '100', '1/10', end=True))[-1] == 100.0
    >>> assert list(frange('1', '100.0', '.1', end=True))[-1] == 100.0
    >>> assert list(frange('1.0', 100, '1e-1', end=True))[-1] == 100.0
    >>> assert list(frange(1, 100.0, 0.1, end=True))[-1] != 100.0
    >>> assert list(frange(1, 100.0, 0.1, end=True, via_str=True))[-1] == 100.0

    """
    if via_str:
        start = str(start)
        stop = str(stop)
        jump = str(jump)
    start = Fraction(start)
    stop = Fraction(stop)
    jump = Fraction(jump)
    while start < stop:
        yield float(start)
        start += jump
    if end and start == stop:
        yield(float(start))

您可以通过运行一些断言来验证所有这些内容:

assert Fraction('1.1') - Fraction(11, 10) == 0.0
assert Fraction( 0.1 ) - Fraction(1, 10) == Fraction(1, 180143985094819840)

assert str(0.1) == '0.1'
assert '%.50f' % 0.1 == '0.10000000000000000555111512312578270211815834045410'

assert list(frange(1, 100.0, '0.1', end=True))[-1] == 100.0
assert list(frange(1.0, '100', '1/10', end=True))[-1] == 100.0
assert list(frange('1', '100.0', '.1', end=True))[-1] == 100.0
assert list(frange('1.0', 100, '1e-1', end=True))[-1] == 100.0
assert list(frange(1, 100.0, 0.1, end=True))[-1] != 100.0
assert list(frange(1, 100.0, 0.1, end=True, via_str=True))[-1] == 100.0

assert list(frange(2, 3, '1/6', end=True))[-1] == 3.0
assert list(frange(0, 100, '1/3', end=True))[-1] == 100.0

GitHub上的代码


4

为什么标准库中没有浮点范围实现?

如此处所有帖子所述,没有的浮点版本range()。就是说,如果我们认为range()函数经常用作索引生成器(当然,这意味着访问器),则省略是有意义的。因此,当我们调用时range(0,40),实际上是说我们想要40个值,从0开始,最多40个,但不包括40个本身。

当我们认为索引的生成与其值的数量一样多时,range()在标准库中使用float实现就没有意义了。例如,如果我们调用该函数frange(0, 10, 0.25),我们希望同时包含0和10,但这将产生一个具有41个值的向量。

因此,frange()取决于其用途的功能将始终表现出与之相反的直观行为。从索引角度看,它要么具有太多值,要么不包括从数学角度应合理返回的数字。

数学用例

如上所述,如上所述,numpy.linspace()可以很好地从数学角度执行生成:

numpy.linspace(0, 10, 41)
array([  0.  ,   0.25,   0.5 ,   0.75,   1.  ,   1.25,   1.5 ,   1.75,
         2.  ,   2.25,   2.5 ,   2.75,   3.  ,   3.25,   3.5 ,   3.75,
         4.  ,   4.25,   4.5 ,   4.75,   5.  ,   5.25,   5.5 ,   5.75,
         6.  ,   6.25,   6.5 ,   6.75,   7.  ,   7.25,   7.5 ,   7.75,
         8.  ,   8.25,   8.5 ,   8.75,   9.  ,   9.25,   9.5 ,   9.75,  10.
])

索引用例

对于索引的观点,我用一些棘手的字符串魔术写了一种略有不同的方法,该魔术使我们可以指定小数位数。

# Float range function - string formatting method
def frange_S (start, stop, skip = 1.0, decimals = 2):
    for i in range(int(start / skip), int(stop / skip)):
        yield float(("%0." + str(decimals) + "f") % (i * skip))

同样,我们也可以使用内置round函数并指定小数位数:

# Float range function - rounding method
def frange_R (start, stop, skip = 1.0, decimals = 2):
    for i in range(int(start / skip), int(stop / skip)):
        yield round(i * skip, ndigits = decimals)

快速比较和性能

当然,经过以上讨论,这些功能的用例相当有限。尽管如此,这是一个快速比较:

def compare_methods (start, stop, skip):

    string_test  = frange_S(start, stop, skip)
    round_test   = frange_R(start, stop, skip)

    for s, r in zip(string_test, round_test):
        print(s, r)

compare_methods(-2, 10, 1/3)

每个结果都相同:

-2.0 -2.0
-1.67 -1.67
-1.33 -1.33
-1.0 -1.0
-0.67 -0.67
-0.33 -0.33
0.0 0.0
...
8.0 8.0
8.33 8.33
8.67 8.67
9.0 9.0
9.33 9.33
9.67 9.67

和一些时间:

>>> import timeit

>>> setup = """
... def frange_s (start, stop, skip = 1.0, decimals = 2):
...     for i in range(int(start / skip), int(stop / skip)):
...         yield float(("%0." + str(decimals) + "f") % (i * skip))
... def frange_r (start, stop, skip = 1.0, decimals = 2):
...     for i in range(int(start / skip), int(stop / skip)):
...         yield round(i * skip, ndigits = decimals)
... start, stop, skip = -1, 8, 1/3
... """

>>> min(timeit.Timer('string_test = frange_s(start, stop, skip); [x for x in string_test]', setup=setup).repeat(30, 1000))
0.024284090992296115

>>> min(timeit.Timer('round_test = frange_r(start, stop, skip); [x for x in round_test]', setup=setup).repeat(30, 1000))
0.025324633985292166

看起来字符串格式化方法在我的系统上胜出。

局限性

最后,通过上面的讨论来说明这一点和最后一个局限性:

# "Missing" the last value (10.0)
for x in frange_R(0, 10, 0.25):
    print(x)

0.25
0.5
0.75
1.0
...
9.0
9.25
9.5
9.75

此外,当skip参数不能被该stop值整除时,考虑到后一个问题,可能会出现打呵欠的间隙:

# Clearly we know that 10 - 9.43 is equal to 0.57
for x in frange_R(0, 10, 3/7):
    print(x)

0.0
0.43
0.86
1.29
...
8.14
8.57
9.0
9.43

有多种方法可以解决此问题,但最终,最好的方法可能是仅使用Numpy。


这是一个非常扭曲的论点。range()应该仅查看迭代生成器,并且应将其用于for循环还是对某些内容建立索引应留给调用方。人们一直在使用花车循环进行千年运动,而以上的论据是没有道理的。Python委员会中的人们在这里忙得不可开交,而好的论点可能会被上述一些扭曲的理由淹没。就是这么简单。现在,Python语言已经做出了太多上述决定。
Shital Shah

3

kichik提供了一个没有numpy等相关性的解决方案,但是由于浮点运算的原因,它的行为常常出乎意料。正如blubberdiblub所说,其他元素很容易潜入结果。例如,naive_frange(0.0, 1.0, 0.1)将产生0.999...作为其最后一个值,因此总共产生11个值。

这里提供了一个强大的版本:

def frange(x, y, jump=1.0):
    '''Range for floats.'''
    i = 0.0
    x = float(x)  # Prevent yielding integers.
    x0 = x
    epsilon = jump / 2.0
    yield x  # yield always first value
    while x + epsilon < y:
        i += 1.0
        x = x0 + i * jump
        yield x

由于相乘,舍入误差不会累积。epsilon即使问题可能会在很小的一端和很大的端头出现,使用use 也会照顾到乘法的舍入误差。现在,正如预期的那样:

> a = list(frange(0.0, 1.0, 0.1))
> a[-1]
0.9
> len(a)
10

而更大的数字:

> b = list(frange(0.0, 1000000.0, 0.1))
> b[-1]
999999.9
> len(b)
10000000

该代码也可以作为GitHub Gist获得


这会因frange(2.0,17.0 / 6.0,1.0 / 6.0)而失败。永远不可能使它健壮。
benrg '16

@benrg感谢您指出这一点!这使我意识到epsilon应该取决于跳跃,因此我回顾了算法并修复了问题。这个新版本更加健壮,不是吗?
阿克塞利·帕伦(AkseliPalén)

2

一个更简单的无库版本

哎呀,我会扔一个简单的无库版本。随时进行改进[*]:

def frange(start=0, stop=1, jump=0.1):
    nsteps = int((stop-start)/jump)
    dy = stop-start
    # f(i) goes from start to stop as i goes from 0 to nsteps
    return [start + float(i)*dy/nsteps for i in range(nsteps)]

核心思想是使nsteps您从头到尾的步骤数,并且range(nsteps)始终发出整数,因此不会损失准确性。最后一步是将[0..nsteps]线性映射到[start..stop]。

编辑

如果您像alancalvitti一样希望系列具有精确的有理表示,则可以随时使用Fractions

from fractions import Fraction

def rrange(start=0, stop=1, jump=0.1):
    nsteps = int((stop-start)/jump)
    return [Fraction(i, nsteps) for i in range(nsteps)]

[*]特别是frange()返回列表,而不是生成器。但这足以满足我的需求。


如果要在输出中包含停止值,则通过添加stop + jump,此方法将恢复为中间浮点差的幼稚结果,frange(0,1.1,0.1)并尝试选择更多类似的选项frange(0,1.05,0.1)
alancalvitti

@alancalvitti:您对“坏”浮点的定义是什么?是的,结果可能无法很好地打印出来,但是frange()提供了在浮点表示法限制内最接近的一组均匀间隔的值。您将如何改善?
fearless_fool19年

好点,我很习惯高级语言,在这种情况下,您会在有理数范围内进行选择,因此Py感觉像是汇编。
alancalvitti

部件?恐怖!;)当然,Python可以用分数提供精确的表示形式:docs.python.org/3/library/fractions.html
fearless_fool

是的,谢谢,但是例如,我喜欢的语言会自动转换这些类型,所以1/2是有理数,而1 / 2.0是浮点数,则无需这样声明它们-将声明留给Java,甚至更多比Py低/组装。
alancalvitti

2

这可以通过numpy.arange(start,stop,stepsize)完成

import numpy as np

np.arange(0.5,5,1.5)
>> [0.5, 2.0, 3.5, 5.0]

# OBS you will sometimes see stuff like this happening, 
# so you need to decide whether that's not an issue for you, or how you are going to catch it.
>> [0.50000001, 2.0, 3.5, 5.0]

注意1: 在此处评论部分的讨论中,“请勿使用numpy.arange()(numpy文档本身建议不要使用它。请按照wim的建议使用numpy.linspace,或此答案中的其他建议之一”)

注意2: 我已在此处阅读了一些评论中的讨论,但是在第三次回到这个问题之后,我认为此信息应该放在更易读的位置。


2

正如kichik所写,这应该不太复杂。但是这段代码:

def frange(x, y, jump):
  while x < y:
    yield x
    x += jump

这是不适当的,因为使用浮点数时错误累积影响。这就是为什么您收到类似以下内容的原因:

>>>list(frange(0, 100, 0.1))[-1]
99.9999999999986

虽然预期的行为是:

>>>list(frange(0, 100, 0.1))[-1]
99.9

解决方案1

使用索引变量可以简单地减少累积误差。例子如下:

from math import ceil

    def frange2(start, stop, step):
        n_items = int(ceil((stop - start) / step))
        return (start + i*step for i in range(n_items))

本示例按预期方式工作。

解决方案2

没有嵌套函数。只有一会儿和一个计数器变量:

def frange3(start, stop, step):
    res, n = start, 1

    while res < stop:
        yield res
        res = start + n * step
        n += 1

此功能也将很好地起作用,除非您想要反向范围。例如:

>>>list(frange3(1, 0, -.1))
[]

在这种情况下,解决方案1将按预期工作。要使此功能在这种情况下起作用,您必须应用类似于以下内容的技巧:

from operator import gt, lt

def frange3(start, stop, step):
    res, n = start, 0.
    predicate = lt if start < stop else gt
    while predicate(res, stop):
        yield res
        res = start + n * step
        n += 1

有了这个技巧,您就可以否定步骤使用这些功能:

>>>list(frange3(1, 0, -.1))
[1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.3999999999999999, 0.29999999999999993, 0.19999999999999996, 0.09999999999999998]

解决方案3

您甚至可以使用普通的标准库走得更远,并为大多数数字类型组成一个范围函数:

from itertools import count
from itertools import takewhile

def any_range(start, stop, step):
    start = type(start + step)(start)
    return takewhile(lambda n: n < stop, count(start, step))

该生成器改编自Fluent Python书(第14章)。Iterables,迭代器和生成器。缩小范围将不起作用。您必须像以前的解决方案一样使用黑客手段。

您可以按如下方式使用此生成器,例如:

>>>list(any_range(Fraction(2, 1), Fraction(100, 1), Fraction(1, 3)))[-1]
299/3
>>>list(any_range(Decimal('2.'), Decimal('4.'), Decimal('.3')))
[Decimal('2'), Decimal('2.3'), Decimal('2.6'), Decimal('2.9'), Decimal('3.2'), Decimal('3.5'), Decimal('3.8')]

当然,您也可以将其与floatint一起使用。

小心

如果要将这些功能用于否定步骤,则应添加对步骤符号的检查,例如:

no_proceed = (start < stop and step < 0) or (start > stop and step > 0)
if no_proceed: raise StopIteration

StopIteration如果要模拟range功能本身,最好的方法是raise 。

模拟范围

如果您想模仿range函数接口,可以提供一些参数检查:

def any_range2(*args):
    if len(args) == 1:
        start, stop, step = 0, args[0], 1.
    elif len(args) == 2:
        start, stop, step = args[0], args[1], 1.
    elif len(args) == 3:
        start, stop, step = args
    else:
        raise TypeError('any_range2() requires 1-3 numeric arguments')

    # here you can check for isinstance numbers.Real or use more specific ABC or whatever ...

    start = type(start + step)(start)
    return takewhile(lambda n: n < stop, count(start, step))

我认为,您已经明白了。你可以用任何的这些功能(除了最前面的一个),去和所有你需要对他们来说是Python标准库。


1

我编写了一个函数,该函数返回范围为双精度浮点数的元组,且没有超过百分之一的小数位。只需解析诸如字符串之类的范围值并将剩余部分分开即可。我用它来显示要从UI中选择的范围。我希望其他人觉得它有用。

def drange(start,stop,step):
    double_value_range = []
    while start<stop:
        a = str(start)
        a.split('.')[1].split('0')[0]
        start = float(str(a))
        double_value_range.append(start)
        start = start+step
    double_value_range_tuple = tuple(double_value_range)
   #print double_value_range_tuple
    return double_value_range_tuple

1

用法

# Counting up
drange(0, 0.4, 0.1)
[0, 0.1, 0.2, 0.30000000000000004, 0.4]

# Counting down
drange(0, -0.4, -0.1)
[0, -0.1, -0.2, -0.30000000000000004, -0.4]

将每一步四舍五入到N个小数位

drange(0, 0.4, 0.1, round_decimal_places=4)
[0, 0.1, 0.2, 0.3, 0.4]

drange(0, -0.4, -0.1, round_decimal_places=4)
[0, -0.1, -0.2, -0.3, -0.4]

def drange(start, end, increment, round_decimal_places=None):
    result = []
    if start < end:
        # Counting up, e.g. 0 to 0.4 in 0.1 increments.
        if increment < 0:
            raise Exception("Error: When counting up, increment must be positive.")
        while start <= end:
            result.append(start)
            start += increment
            if round_decimal_places is not None:
                start = round(start, round_decimal_places)
    else:
        # Counting down, e.g. 0 to -0.4 in -0.1 increments.
        if increment > 0:
            raise Exception("Error: When counting down, increment must be negative.")
        while start >= end:
            result.append(start)
            start += increment
            if round_decimal_places is not None:
                start = round(start, round_decimal_places)
    return result

为什么选择这个答案?

  • 当要求倒计时时,许多其他答案将挂起。
  • 许多其他答案将给出错误的舍入结果。
  • 其他答案np.linspace都是反复无常的,由于难以选择正确的除法数,它们可能会起作用,也可能不会起作用。np.linspace十进制增量为0.1确实很困难,公式中将增量转换为多个拆分的除法顺序可能会导致代码正确或损坏。
  • np.arange不建议使用其他答案。

如有疑问,请尝试上述四个测试案例。


0
def Range(*argSequence):
    if len(argSequence) == 3:
        imin = argSequence[0]; imax = argSequence[1]; di = argSequence[2]
        i = imin; iList = []
        while i <= imax:
            iList.append(i)
            i += di
        return iList
    if len(argSequence) == 2:
        return Range(argSequence[0], argSequence[1], 1)
    if len(argSequence) == 1:
        return Range(1, argSequence[0], 1)

请注意,Range的首字母为大写。Python中的函数不建议使用此命名方法。您可以根据需要将Range更改为drange或frange。“范围”功能的行为与您想要的一样。您可以在这里查看它的手册[ http://reference.wolfram.com/language/ref/Range.html ]。


0

我认为有一个非常简单的答案可以真正模拟范围的所有功能,但对于浮点数和整数而言。在此解决方案中,您仅假设默认情况下的近似值为1e-7(或您选择的近似值),并且可以在调用函数时对其进行更改。

def drange(start,stop=None,jump=1,approx=7): # Approx to 1e-7 by default
  '''
  This function is equivalent to range but for both float and integer
  '''
  if not stop: # If there is no y value: range(x)
      stop= start
      start= 0
  valor= round(start,approx)
  while valor < stop:
      if valor==int(valor):
          yield int(round(valor,approx))
      else:
          yield float(round(valor,approx))
      valor += jump
  for i in drange(12):
      print(i)

0

当然会有一些舍入错误,所以这不是完美的,但这是我通常用于不需要高精度的应用程序的方法。如果要使其更准确,可以添加一个额外的参数来指定如何处理舍入错误。传递舍入函数也许可以使其扩展,并允许程序员指定如何处理舍入错误。

arange = lambda start, stop, step: [i + step * i for i in range(int((stop - start) / step))]

如果我写:

arange(0, 1, 0.1)

它将输出:

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]

-1

在Python中是否有一个等效于float的range()?否使用此:

def f_range(start, end, step):
    a = range(int(start/0.01), int(end/0.01), int(step/0.01))
    var = []
    for item in a:
        var.append(item*0.01)
    return var

3
相当糟糕的解决方案,请尝试f_range(0.01,0.02,0.001)...对于大多数实际目的,arangeNumpy是一种简单,安全且快速的解决方案。
巴特

你是对的。使用numpy比我的代码快1.8。
Grigor Kolev

你是对的。使用numpy比我的代码快1.8。但是我工作的系统是完全封闭的。只有Python和pyserial而已。
Grigor Kolev

-2

这里有几个答案不能处理简单的极端情况,例如负步,错误的启动,停止等。这是正确处理许多情况的版本,具有与native相同的行为range()

def frange(start, stop=None, step=1):
  if stop is None:
    start, stop = 0, start
  steps = int((stop-start)/step)
  for i in range(steps):
    yield start
    start += step  

请注意,这将错误出step = 0,就像native一样range。区别之一是本机范围返回的对象是可索引的和可逆的,而上面的对象则不是。

您可以在此处使用此代码和测试用例。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.