步长为 float 类型的范围

发布于 2024-10-02 10:27:00 字数 596 浏览 0 评论 0原文

文档基本上说 range 的行为必须完全相同此实现(对于正步骤):

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

它还表明其参数必须是整数。这是为什么?如果步骤是浮点数,这个定义不是也完全有效吗?

就我而言,我尤其如此。需要一个 range 函数,该函数接受 float 类型作为其 step 参数。 Python 有吗?还是我需要自己实现?


更具体地说:我如何以一种很好的方式将这个 C 代码直接转换为 Python(即不仅仅是通过 while 循环手动执行):

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

The documentation basically says that range must behave exactly as this implementation (for positive step):

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

It also says that its arguments must be integers. Why is that? Isn't that definition also perfectly valid if step is a float?

In my case, I am esp. needing a range function which accepts a float type as its step argument. Is there any in Python or do I need to implement my own?


More specific: How would I translate this C code directly to Python in a nice way (i.e. not just doing it via a while-loop manually):

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

泼猴你往哪里跑 2024-10-09 10:27:00

您可以使用 numpy.arange

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

You could use numpy.arange.

EDIT: The docs prefer numpy.linspace. Thanks @Droogans for noticing =)

花桑 2024-10-09 10:27:00

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

range(0, 0.4, 0.1)

您可能期望输出为

[0, 0.1, 0.2, 0.3]

,但实际上

[0, 0.1, 0.2000000001, 0.3000000001]

由于舍入问题,您会得到类似的结果。由于范围经常用于生成某种类型的索引,因此它只是整数。

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

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

One explanation might be floating point rounding issues. For example, if you could call

range(0, 0.4, 0.1)

you might expect an output of

[0, 0.1, 0.2, 0.3]

but you in fact get something like

[0, 0.1, 0.2000000001, 0.3000000001]

due to rounding issues. And since range is often used to generate indices of some sort, it's integers only.

Still, if you want a range generator for floats, you can just roll your own.

def xfrange(start, stop, step):
    i = 0
    while start + i * step < stop:
        yield start + i * step
        i += 1
初与友歌 2024-10-09 10:27:00

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

In order to be able to use decimal numbers in a range expression a cool way for doing it is the following:
[x * 0.1 for x in range(0, 10)]

女皇必胜 2024-10-09 10:27:00

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

你真正想要的是算术级数;下面的代码对于 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)

更正:这里有一个竞争性运行总计小工具

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
>>>

The problem with floating point is that you may not get the same number of items as you expected, due to inaccuracy. This can be a real problem if you are playing with polynomials where the exact number of items is quite important.

What you really want is an arithmetic progression; the following code will work quite happily for int, float and complex ... and strings, and lists ...

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

Note that this code stands a better chance of your last value being within a bull's roar of the expected value than any alternative which maintains a running total.

>>> 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)

Correction: here's a 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
>>>
埋葬我深情 2024-10-09 10:27:00

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

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

When you add floating point numbers together, there's often a little bit of error. Would a range(0.0, 2.2, 1.1) return [0.0, 1.1] or [0.0, 1.1, 2.199999999]? There's no way to be certain without rigorous analysis.

The code you posted is an OK work-around if you really need this. Just be aware of the possible shortcomings.

停顿的约定 2024-10-09 10:27:00

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

 [ (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]

Here is a special case that might be good enough:

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

In your case this would be:

#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'

and so:

>>> [ .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]
痴情 2024-10-09 10:27:00

这就是我会使用的:

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]

希望它有帮助。

This is what I would use:

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

rather than:

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]

hope it helps.

二手情话 2024-10-09 10:27:00

可能是因为你不能拥有可迭代的一部分。此外,float 并不精确。

Probably because you can't have part of an iterable. Also, floats are imprecise.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文