【问题标题】:Range with step of type float [duplicate]具有浮点类型步长的范围[重复]
【发布时间】:2011-05-10 12:56:54
【问题描述】:

The documentation 基本上说range 的行为必须与此实现完全相同(对于积极的step):

def range(start, stop, step):
  x = start
  while True:
    if x >= stop: return
    yield x
    x += step

它还说它的参数必须是整数。这是为什么?如果 step 是浮点数,这个定义不是也完全有效吗?

就我而言,我是 esp。需要一个接受浮点类型作为其step 参数的range 函数。 Python中有没有,还是我需要自己实现?


更具体:我如何以一种很好的方式将这段 C 代码直接翻译成 Python(即,不只是通过 while-loop 手动完成):

for(float x = 0; x < 10; x += 0.5f) { /* ... */ }

【问题讨论】:

  • 循环中不能有returnyield 关键字,请使用break
  • 看起来可以!我不认为这是可能的.. 我确信当我尝试类似的事情时已经引发了错误
  • 以您发布的代码示例为例,将其重命名为float_range - 完成。
  • @Tim: return 变为 raise StopIteration; return &lt;expression&gt; 得到 SyntaxError: 'return' with argument inside generator——即使是 return None
  • 其实range()返回的是一个列表。 OP描述的其实是xrange(),每次返回一个元素。

标签: python range


【解决方案1】:

你可以使用numpy.arange

编辑:文档更喜欢numpy.linspace感谢@Droogans 的关注 =)

【讨论】:

  • 第一段指出:当使用非整数步长时,例如0.1,结果往往会不一致。对于这些情况,最好使用linspace
  • 注意linspace有不同的接口。
  • 甚至没有 numpy.arange。我做了一个没有浮点精度问题的 xfrange 函数。看看 ;) stackoverflow.com/questions/477486/…
【解决方案2】:

一种解释可能是浮点舍入问题。例如,如果您可以调用

range(0, 0.4, 0.1)

你可能期望输出

[0, 0.1, 0.2, 0.3]

但实际上你得到了类似的东西

[0, 0.1, 0.2000000001, 0.3000000001]

由于舍入问题。而且由于 range 经常用于生成某种索引,所以它只是整数。

不过,如果您想要一个浮点范围生成器,您可以自己滚动。

def xfrange(start, stop, step):
    i = 0
    while start + i * step < stop:
        yield start + i * step
        i += 1

【讨论】:

  • 当然可以(它的行为方式很自然)。浮点数总是如此。所以当然,如果range 支持浮点数,它会以这种方式运行,这完全是合法的。所以我真的不明白为什么不应该这样做。
  • @Albert:通常没有必要想知道为什么会做出这样的决定。他们只是。在这种情况下,有限的用例将被潜在的讨厌的错误所抵消。
  • 您正在累积舍入误差。请改用这个:` i = 0; r = start while r
  • @josch 我显然错过了 Cees 的评论。你当然是绝对正确的,我的版本会疯狂地累积舍入误差。事实上,我有点不安重新审视它,因为这显然是错误的事情!但它现在 - 终于 - 修复了。谢谢你提醒我。
  • 否定的step 坏了,像这样修复你的while 条件:while (start + i * step) * (-1 if step &lt; 0 else 1) &lt; stop:
【解决方案3】:

为了能够在范围表达式中使用十进制数,一种很酷的方法如下: [x * 0.1 for x in range(0, 10)]

【讨论】:

  • 如果您的“范围”有很多数字并且您的 0.1 的“步长”较小,例如 0.00000001,那么这将不起作用,脚本只会挂在大多数计算机上。我们将需要一些模拟 xrange 所做的事情。即。我们需要一个可迭代/生成器,而不是列出上面的 comprehension.fxrange 范围在这种情况下效果更好。
  • 非常简单的列表理解解决方案,谢谢!
  • @ekta 使用 () 而不是 [] 将其变成生成器。
  • 我只需要原生 range 所期望的一些简单的东西——我对这个解决方案很满意
【解决方案4】:

浮点的问题在于,由于不准确,您可能无法获得与预期相同数量的项目。如果您正在使用多项式,其中项目的确切数量非常重要,这可能是一个真正的问题。

你真正想要的是算术级数;以下代码对于intfloatcomplex ... 以及字符串和列表...

def arithmetic_progression(start, step, length):
    for i in xrange(length):
        yield start + i * step

请注意,与保持运行总数的任何替代方案相比,此代码更有可能使您的最后一个值处于预期值的牛市咆哮之内。

>>> 10000 * 0.0001, sum(0.0001 for i in xrange(10000))
(1.0, 0.9999999999999062)
>>> 10000 * (1/3.), sum(1/3. for i in xrange(10000))
(3333.333333333333, 3333.3333333337314)

更正:这是competetive running-total gadget

def kahan_range(start, stop, step):
    assert step > 0.0
    total = start
    compo = 0.0
    while total < stop:
        yield total
        y = step - compo
        temp = total + y
        compo = (temp - total) - y
        total = temp

>>> list(kahan_range(0, 1, 0.0001))[-1]
0.9999
>>> list(kahan_range(0, 3333.3334, 1/3.))[-1]
3333.333333333333
>>>

【讨论】:

  • 这是一个绝妙的答案。为什么它没有得到比累积不精确或需要额外库的答案更多的支持?
【解决方案5】:

当您将浮点数相加时,通常会出现一些错误。 range(0.0, 2.2, 1.1) 会返回 [0.0, 1.1] 还是 [0.0, 1.1, 2.199999999]?没有严谨的分析,就无法确定。

如果您确实需要,您发布的代码是一个不错的解决方法。请注意可能存在的缺点。

【讨论】:

  • 是的,有办法确定。当您在内存中表示为双浮点数时,您的 1.1 步长正好是 0x1.199999999999ap+0。 OP 发布的代码并不是一个完美的解决方法,因为重复添加不精确的值会使错误累积。正如其他答案已经显示的那样,在迭代期间跟踪循环数并将步长乘以循环数是一个更好的主意。
  • @josch 我指的是一般情况,而不是具体的数字。
  • 那么我们对“某些”的定义就不同了。即使使用浮点数,计算机也不会给您“不确定”或“随机”的结果。结果将始终是确定性的。无论输入如何,给定任何有限的浮点数,在以给定的精度将它们相加 X 次后,您总能肯定地说出它们的结果。
  • @josch 我根据您的反馈进行了一些修改,谢谢。
  • 现在说得通了。谢谢!
【解决方案6】:

这是一个可能足够好的特殊情况:

 [ (1.0/divStep)*x for x in range(start*divStep, stop*divStep)]

在你的情况下,这将是:

#for(float x = 0; x < 10; x += 0.5f) { /* ... */ } ==>
start = 0
stop  = 10
divstep = 1/.5 = 2 #This needs to be int, thats why I said 'special case'

等等:

>>> [ .5*x for x in range(0*2, 10*2)]
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]

【讨论】:

    【解决方案7】:

    这是我会使用的:

    numbers = [float(x)/10 for x in range(10)]
    

    而不是:

    numbers = [x*0.1 for x in range(10)]
    that would return :
    [0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]
    

    希望对你有帮助。

    【讨论】:

    • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post
    • @RaisAlam 请注意,如果他使用 0.5 而不是 0.1,则不会出现意外行为。
    【解决方案8】:

    可能是因为您不能拥有可迭代对象的一部分。此外,floats 也不精确。

    【讨论】:

    • 浮点数非常精确。他们不擅长的是表示某些在基数 10 中具有有限表示的值。例如,基数 10 中的 0.1 将在您的内存中变为 0x1.999999999999ap-4(使用精确的十六进制浮点表示),而不是十进制的 0.1 .有了这个论点,你也可以说十进制数是不精确的,因为它们对某些值没有有限的表示......
    猜你喜欢
    • 2016-05-13
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-22
    • 2023-04-01
    • 2023-03-29
    相关资源
    最近更新 更多