Python 浮动的范围()

Python 浮动的范围(),python,range,fractions,decimal,Python,Range,Fractions,Decimal,Python中的浮点是否有一个range()等价物 >>> 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 mu

Python中的浮点是否有一个
range()
等价物

>>> 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
>范围(0.5,5,1.5)
[0, 1, 2, 3, 4]
>>>范围(0.5,5,0.5)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
范围(0.5,5,0.5)
ValueError:range()步骤参数不能为零
我不知道一个内置函数,但写这样的函数(https://stackoverflow.com/a/477610/623735)不应该太复杂。
def frange(x, y, jump):
  while x < y:
    yield x
    x += jump
要获得预期结果,您可以使用此问题中的其他答案之一,或者如@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)
[编者注:如果只使用正的
跳转
和整数开始和停止(
x
y
),这很好。有关更一般的解决方案,请参阅。]

您可以使用:

[x / 10.0 for x in range(5, 50, 15)]
或者使用lambda/map:

map(lambda x: x/10.0, range(5, 50, 15))
热切评估(2.x
范围
):

延迟评估(2.x
xrange
,3.x
range
):

或者:

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

我曾经使用
numpy.arange
,但由于浮点错误,在控制返回的元素数量时遇到了一些麻烦。所以现在我使用
linspace
,例如:

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

Pylab有
frange
(实际上是一个包装器,用于
matplotlib.mlab.frange
):


我编写了一个函数,它返回一系列双精度浮点数的元组,小数点不超过百分之一百。这只是一个像字符串一样解析范围值并分离多余值的问题。我使用它来显示从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
def排放(启动、停止、步骤):
双_值_范围=[]

使用
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]
>>来自itertools导入计数,takewhile
>>>def法兰(启动、停止、步骤):
返回takewhile(λx:x<停止,计数(开始,步骤))
>>>清单(法兰格(0.5,5,1.5))
# [0.5, 2.0, 3.5]
A是由kichik提供的,但由于以下原因,它的行为常常出人意料。如和所述,其他元素很容易潜入结果中。例如,
naive\u 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
而且数字稍大一些:

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

代码也可用作。

没有这样的内置函数,但是您可以使用以下(Python 3代码)尽可能安全地完成这项工作

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))
def范围(*argSequence)上的代码可用: 如果len(argSequence)==3: imin=argSequence[0];imax=argSequence[1];di=arg序列[2] i=亚胺;iList=[] 而我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
我帮助将该功能添加到包中

更多工具。数值范围(开始、停止、步进)
与内置函数范围类似,但可以处理浮点、小数和小数类型

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

我认为有一个非常简单的答案,它真正模拟了range的所有特性,但同时适用于float和integer。在此解决方案中,您只需假设默认近似值为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)
def drange(启动、停止=无、跳转=1、大约=7):#默认情况下大约为1e-7
'''
此函数等效于范围,但同时适用于浮点和整数
'''
如果不停止:#如果没有y值:范围(x)
停止=开始
开始=0
valor=圆形(起点,近似值)
当英勇<停止:
如果valor==int(valor):
收益率整数(圆形(近似值))
其他:
收益浮动(圆形(价值,近似值))
勇气+=跳跃
对于我在德兰奇(12):
印刷品(一)

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

这里所有的帖子都清楚地表明,
range()
没有浮点版本。也就是说,如果我们认为<>代码> Range[Audio](/Case>函数)经常用作索引(当然,这意味着一个访问器)生成器,那么省略是有意义的。所以,当我们调用
范围(0,40)
时,我们实际上是说我们想要40个值,从0开始,直到40,但不包括40本身

当我们认为索引生成与其索引的数量一样多时,在标准库中使用“代码>Range[())/代码>的浮点实现是没有意义的。例如,如果我们调用函数

frange(0,10,0.25)
,我们希望同时包含0和10,但这将生成一个包含41个值的生成器,而不是
10/0.25
中的40个值

因此,根据其用途,
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)
快速比较和性能

当然,考虑到上面的讨论,这些函数有一个相当有限的用例。尽管如此,这里还是有一个问题
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
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)
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
>>> from more_itertools import numeric_range
>>> tuple(numeric_range(.1, 5, 1))
(0.1, 1.1, 2.1, 3.1, 4.1)
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)
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))
# 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
# 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
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)]
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)]
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  
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]
# 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]
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
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
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))
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))
[]
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]
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))
>>>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')]
no_proceed = (start < stop and step < 0) or (start > stop and step > 0)
if no_proceed: raise StopIteration
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))
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]
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.]])]
>>> 3*.1 > .3  # 0.30000000000000004
True

>>> 3*.3 < 0.9  # 0.8999999999999999
True
>>> (3*.1).as_integer_ratio()
(1351079888211149, 4503599627370496)
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)