range() 用于浮点数

2025-02-07 08:44:00
admin
原创
74
摘要:问题描述: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 &qu...

问题描述:

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:

您可以使用:

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

或者使用 lambda/map:

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

解决方案 2:

我不知道内置函数,但是编写像[这个](https://stackoverflow.com/a/477610/623735)这样的函数应该不会太复杂。

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

[编者注:如果你只使用正整数jump和整数开始和停止(xy),那么这种方法就很好。有关更通用的解决方案,请参见此处。]

解决方案 3:

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

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

解决方案 4:

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

解决方案 5:

热切评估(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.

解决方案 6:

使用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]

解决方案 7:

我不知道这个问题是否老旧,但库arange中有一个函数NumPy,它可以作为一个范围工作。

np.arange(0,1,0.1)

#out: 

array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

解决方案 8:

我帮助将函数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)

解决方案 9:

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

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

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 将按预期工作。要使此功能在这种情况下工作,您必须应用类似于以下内容的 hack:

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 章。可迭代对象、迭代器和生成器)。它不适用于递减范围。您必须像上一个解决方案一样应用 hack。

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

>>>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函数本身,那么最好的选择是提高。

模仿范围

如果您想模仿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 标准库。

解决方案 10:

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
        if x < y:
          yield x

由于乘法,舍入误差不会累积。使用epsilon可以解决乘法可能出现的舍入误差,尽管问题当然可能出现在非常小和非常大的两端。现在,正如预期的那样:

> 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使用。

解决方案 11:

没有这样的内置函数,但您可以使用以下内容(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上获取

解决方案 12:

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

正如这里所有帖子所明确指出的那样,没有浮点版本range()。也就是说,如果我们考虑到该range()函数通常用作索引(当然,这意味着访问器)生成器,那么省略是有意义的。因此,当我们调用时range(0,40),我们实际上是在说我们想要从 0 开始到 40 的 40 个值,但不包括 40 本身。

当我们认为索引生成不仅与索引值有关,还与索引数量有关时,使用range()标准库中的浮点实现就没有什么意义了。例如,如果我们调用函数frange(0, 10, 0.25),我们期望包含 0 和 10,但这将产生一个具有 41 个值的生成器,而不是可能期望的 40 个10/0.25

因此,根据其用途,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。

解决方案 13:

更简单的无库版本

哎呀,见鬼——我会添加一个简单的无库版本。欢迎随意改进它[*]:

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一样希望该系列具有精确的合理表示,那么您可以随时使用分数:

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()返回一个列表,而不是生成器。但它足以满足我的需求。

解决方案 14:

这可以用 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:我已阅读此处几条评论中的讨论,但现在第三次回到这个问题后,我觉得这些信息应该放在更易读的位置。

解决方案 15:

用法

# 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已被弃用。

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

解决方案 16:

我编写了一个函数,它返回一个双精度浮点数范围的元组,该元组没有百分位以外的小数。它只是解析范围值(如字符串)并分离多余的值。我使用它来显示范围以在 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

解决方案 17:

虽然基于整数的范围在“所见即所得”的意义上定义明确,但是有些在浮点数中不容易看到的东西会给在所需范围内获得看似明确定义的行为带来麻烦。

可以采取两种方法:

  1. 将给定范围拆分为一定数量的段:当您选择不能很好划分跨度的点数时,您会接受大量小数位数的 linspace 方法(例如,7 步从 0 到 1 将给出第一步值为 0.14285714285714285)

  2. 给出您已经知道应该有效并希望它能起作用的所需 WYSIWIG 步长。您的希望常常会因获得的值与您想要达到的终点不符而破灭。

倍数可能高于或低于您的预期:

>>> 3*.1 > .3  # 0.30000000000000004
True

>>> 3*.3 < 0.9  # 0.8999999999999999
True

您将尝试通过添加步骤的倍数而不是递增来避免累积错误,但问题始终存在,如果您在纸上手工完成,您将无法获得预期的结果 - 带有精确的小数。但您知道这应该是可能的,因为 Python 向您展示了0.1接近 0.1 的近似值,而不是底层整数比率:

>>> (3*.1).as_integer_ratio()
(1351079888211149, 4503599627370496)

在提供的答案方法中,这里 使用分数并将输入处理为字符串是最好的。我有几个建议可以让它变得更好:

  1. 让它处理类似范围的默认值,这样你就可以自动从 0 开始

  2. 让它处理减少的范围

  3. 使输出看起来像你使用精确算术时所期望的那样

我提供了一个例程,它可以完成同样的任务,但不使用 Fraction 对象。相反,它用于round创建数字,这些数字的显示位数与使用 Python 打印的数字相同,例如,对于 0.1 这样的数字,显示 1 个小数;对于 0.004 这样的数字,显示 3 个小数:

def frange(start, stop, step, n=None):
    """return a WYSIWYG series of float values that mimic range behavior
    by excluding the end point and not printing extraneous digits beyond
    the precision of the input numbers (controlled by n and automatically
    detected based on the string representation of the numbers passed).

    EXAMPLES
    ========

    non-WYSIWYS simple list-comprehension

    >>> [.11 + i*.1 for i in range(3)]
    [0.11, 0.21000000000000002, 0.31]

    WYSIWYG result for increasing sequence

    >>> list(frange(0.11, .33, .1))
    [0.11, 0.21, 0.31]

    and decreasing sequences

    >>> list(frange(.345, .1, -.1))
    [0.345, 0.245, 0.145]

    To hit the end point for a sequence that is divisibe by
    the step size, make the end point a little bigger by
    adding half the step size:

    >>> dx = .2
    >>> list(frange(0, 1 + dx/2, dx))
    [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]

    """
    if step == 0:
        raise ValueError('step must not be 0')
    # how many decimal places are showing?
    if n is None:
        n = max([0 if '.' not in str(i) else len(str(i).split('.')[1])
                for i in (start, stop, step)])
    if step*(stop - start) > 0:  # a non-null incr/decr range
        if step < 0:
            for i in frange(-start, -stop, -step, n):
                yield -i
        else:
            steps = round((stop - start)/step)
            while round(step*steps + start, n) < stop:
                steps += 1
            for i in range(steps):
                yield round(start + i*step, n)

解决方案 18:

我在绘制 y 轴上的概率时遇到了同样的问题。我用过这个:

list(map(lambda x : x.round(1), np.linspace(0.0, 1.0, num=6)))

得出的结果为:

[0.0, 0.2, 0.4, 0.6, 0.8, 1.0]

您可以玩round()小数部分。

解决方案 19:

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 之类的名称。Range 函数的行为完全符合您的要求。您可以在此处查看其手册 [ http://reference.wolfram.com/language/ref/Range.html ]。

解决方案 20:

我认为有一个非常简单的答案可以真正模拟范围的所有功能,但对于浮点数和整数都是如此。在这个解决方案中,你只是假设你的近似值默认为 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)

解决方案 21:

真是小题大做。如果您放宽对函数进行浮点模拟的要求range,而只是创建一个易于在for循环中使用的浮点列表,那么编码就简单而可靠了。

def super_range(first_value, last_value, number_steps):
    if not isinstance(number_steps, int):
        raise TypeError("The value of 'number_steps' is not an integer.")
    if number_steps < 1:
        raise ValueError("Your 'number_steps' is less than 1.")

    step_size = (last_value-first_value)/(number_steps-1)

    output_list = []
    for i in range(number_steps):
        output_list.append(first_value + step_size*i)
    return output_list

first = 20.0
last = -50.0
steps = 5

print(super_range(first, last, steps))

输出将是

[20.0, 2.5, -15.0, -32.5, -50.0]

请注意,该函数super_range不仅限于浮点数。它可以处理定义了运算符+-*和的任何数据类型/,例如complexDecimalnumpy.array

import cmath
first = complex(1,2)
last = complex(5,6)
steps = 5

print(super_range(first, last, steps))

from decimal import *
first = Decimal(20)
last = Decimal(-50)
steps = 5

print(super_range(first, last, steps))

import numpy as np
first = np.array([[1, 2],[3, 4]])
last = np.array([[5, 6],[7, 8]])
steps = 5

print(super_range(first, last, steps))

输出将是:

[(1+2j), (2+3j), (3+4j), (4+5j), (5+6j)]
[Decimal('20.0'), Decimal('2.5'), Decimal('-15.0'), Decimal('-32.5'), Decimal('-50.0')]
[array([[1., 2.],[3., 4.]]),
 array([[2., 3.],[4., 5.]]),
 array([[3., 4.],[5., 6.]]),
 array([[4., 5.],[6., 7.]]),
 array([[5., 6.],[7., 8.]])]

解决方案 22:

Python 中是否有与浮点数等效的 range()?没有,请使用这个:

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

解决方案 23:

哇。你们真的想太多了。

你在做什么?你真的需要一个范围内的步骤列表吗,还是你只是检查一个浮点数是否在其他两个浮点数的范围内?

解析视频时,我经常需要检查 splice_point 是否在某个 PTS 范围内。我只需这样做

    if start < splice_point < stop:

如果您需要检查以下步骤:

  def in_range_with_step(splice_point,start,stop,step):
     if start < splice_point < stop:
         if (splice_point -start) % step ==0:
             return True
     return False

如果你只想要范围内的步骤:

    def a_range(start,stop,step):
        the_range=[]
        while start < stop:  
            the_range.append(start)
            start+=step
       return the_range   

解决方案 24:

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

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]

解决方案 25:

这里有几个答案不能处理简单的边缘情况,如负面步骤、错误启动、停止等。以下版本可以正确处理许多此类情况,并产生与本机相同的行为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。一个区别是 native range 返回可索引和可​​逆的对象,而上面的则不是。

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

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用