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 "<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
和整数开始和停止(x
和y
),那么这种方法就很好。有关更通用的解决方案,请参见此处。]
解决方案 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')]
当然您也可以将它与float和int一起使用。
当心
如果您想以负数步骤使用这些函数,则应添加步骤符号检查,例如:
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:
虽然基于整数的范围在“所见即所得”的意义上定义明确,但是有些在浮点数中不容易看到的东西会给在所需范围内获得看似明确定义的行为带来麻烦。
可以采取两种方法:
将给定范围拆分为一定数量的段:当您选择不能很好划分跨度的点数时,您会接受大量小数位数的 linspace 方法(例如,7 步从 0 到 1 将给出第一步值为 0.14285714285714285)
给出您已经知道应该有效并希望它能起作用的所需 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)
在提供的答案方法中,这里 使用分数并将输入处理为字符串是最好的。我有几个建议可以让它变得更好:
让它处理类似范围的默认值,这样你就可以自动从 0 开始
让它处理减少的范围
使输出看起来像你使用精确算术时所期望的那样
我提供了一个例程,它可以完成同样的任务,但不使用 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
不仅限于浮点数。它可以处理定义了运算符+
、-
、*
和的任何数据类型/
,例如complex
、Decimal
和numpy.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 返回可索引和可逆的对象,而上面的则不是。
您可以在此处使用此代码和测试用例。