수레에 대한 range ()


140

range()파이썬에서 float에 해당 하는 것이 있습니까?

>>> 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
그것들은 분수가 아니라 수레입니다. 그리고 수레는 ... 글쎄요, 예상과 다른 결과를 낼 것입니다.

6
빠른 해결 방법은 정수를 소수로 처리하는 것입니다 (예 range(5, 50, 5)
:)

@delnan-업데이트되었습니다. 플로트 범위의 편의를 위해 미세한 부정확성을 기꺼이 받아들입니다.
Jonathan


@NullUserException-이것은 단지 예일뿐입니다-실제 코드는 물론 파라 메트릭입니다 :)
Jonathan

답변:


97

나는이 내장 된 기능 모르겠지만, 같은 한 서면 너무 복잡하지 않아야합니다.

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. float 대신 문자열로 초기화하십시오.

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

34
파이썬의 모토는 실제로 하나의 명백한 방법이 있어야합니다 . 그러나 파이썬의 어쨌든 :)
Jonathan

3
>>> print list(frange(0,100,0.1))[-1]==100.0될 것입니다False
Volodimir Kopey

frange예기치 않게 작동 할 수 있습니다. 부동 소수점 산술저주 로 인해 예를 들어 frange(0.0, 1.0, 0.1)마지막 값이 11 인 11 개의 값이 생성 0.9999999999999999됩니다. while x + sys.float_info.epsilon < y:비록 이것조차도 많은 숫자로 실패 할 수 있지만 실제적인 개선 이 될 것입니다 .
Akseli Palén

10
-1 내 인생에 영향을 줄 수있는 소프트웨어에는 이 코드를 사용하지 마십시오 . 안정적으로 작동하게하는 방법은 없습니다. Akseli Palén의 답변도 사용하지 마십시오. Xaerxess 또는 wim의 답변을 사용하십시오 (범위에 대한 부분은 무시하십시오).
benrg

3
수레 대신 단계로 사용decimal.Decimal 하면 효과적 입니다.
Tadhg McDonald-Jensen 1

112

다음 중 하나를 사용할 수 있습니다.

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

또는 람다 /지도를 사용하십시오 :

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

1
numpy 배열에는 나누기, 곱하기 등을 처리하는 연산자가 있으므로 array (range (5,50,15)) / 10.0
edvaldig

2
@ edvaldig : 당신 말이 맞아요, 나는 이것에 대해 몰랐습니다 ... 그럼에도 불구하고 arange(0.5, 5, 1.5)IMO가 더 읽기 쉽다고 생각 합니다.
Xaerxess

2
제시된 첫 번째 두 솔루션은 정수를 반복하고 정수에서 최종 부동 소수점을 도출하는 것을 기반으로하기 때문에 허용되는 것 보다이 대답을 선호합니다. 이것은 더 강력합니다. 플로트를 사용하여 직접 수행하는 경우 내부적으로 플로트가 표시되는 방식으로 인해 일회성 오류가 발생할 위험이 있습니다. 예를 들어, 시도 list(frange(0, 1, 0.5))하면 제대로 작동하고 1은 제외되지만 시도 list(frange(0, 1, 0.1))하면 마지막 값은 1.0에 가깝습니다. 아마도 원하는 것이 아닙니다. 여기에 제시된 솔루션에는이 문제가 없습니다.
blubberdiblub

3
numpy.arange를 사용하지 마십시오 (numpy 설명서 자체에서 권장하지 않음). wim에서 권장하는 numpy.linspace 또는이 답변의 다른 제안 중 하나를 사용하십시오.
benrg

79

예전에는 사용 numpy.arange했지만 부동 소수점 오류로 인해 반환되는 요소 수를 제어하는 데 약간의 문제가있었습니다. 이제는 다음과 같이 사용합니다 linspace.

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

그래도 다음과 같이 사용하지 않고 부동 소수점 오류가 여전히 있습니다 decimal.np.linspace(-.1,10,num=5050)[0]
TNT

2
@TNT 아니요, 오류가 아닙니다. 당신 np.linspace(-.1,10,num=5050)[0] == -.1은 사실입니다 찾을 수 있습니다. 단지 repr(np.float64('-0.1'))더 많은 자릿수가 표시됩니다.
wim

1
이 특정 예제는 초과 반올림 오류를 나타내지 않지만 실패 사례가 있습니다. 예를 들어 이상적인 결과가 이면 print(numpy.linspace(0, 3, 148)[49])인쇄 0.9999999999999999합니다 1.0. linspace보다 훨씬 나은 작업을 수행 arange하지만 가능한 최소 반올림 오류가 발생하지는 않습니다.
user2357112는 10

되는 올바른 엔드 포인트 처리를 수행하기 위해 보장, 항상 요소를 정확히 요청 수를 생산하고 있습니다.
user2357112는 Monica

40

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

4
matplotlib 버전 2.2부터는 더 이상 사용되지 않습니다. numpy.arange를 사용해야합니다.
kuzavas

13

열심히 평가 (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.

4
+1; 그러나 왜 (x * .5 for x in range(10))게으른 평가를위한 발전기 표현이 아닌가?
Tim Pietzcker

2
너무 쉬울 것 같아요? :)
Karl Knechtel

11

사용 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]

3
사용하는 일 itertools.takewhile. 그러나 itertools.count(start, step)누적 부동 소수점 오류가 발생합니다. ( takewhile(lambda x: x < 100, count(0, 0.1))예를 들어 평가하십시오 .) takewhile(lambda x: x < stop, (start + i * step for i in count()))대신 쓸 것입니다.
musiphil

6

패키지 more-itertools에 numeric_range 함수를 추가하는 것을 도왔습니다 .

more_itertools.numeric_range(start, stop, step) 내장 함수 범위처럼 작동하지만 float, Decimal 및 Fraction 유형을 처리 할 수 ​​있습니다.

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

4

이러한 내장 함수는 없지만 다음 (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에서 사용 가능한 코드


4

표준 라이브러리에 부동 소수점 범위 구현이없는 이유는 무엇입니까?

여기의 모든 게시물에서 알 수 있듯이의 부동 소수점 버전은 없습니다 range(). 즉, range()함수가 종종 인덱스 생성기 ( 즉, 접근 자를 의미 함 ) 로 사용 된다고 생각하면 생략이 의미가 있습니다. 따라서 우리가을 호출 range(0,40)하면 실제로는 0에서 40까지의 40 값을 원하지만 40을 포함하지 않는 40 개의 값을 원한다고 말합니다.

인덱스 생성이 값만큼 인덱스의 수에 관한 것이라고 생각할 때 range()표준 라이브러리에서 float 구현을 사용하는 것은 의미가 없습니다. 예를 들어 함수를 호출하면frange(0, 10, 0.25) 0과 10이 모두 포함되지만 41 개의 값을 가진 벡터가 생성됩니다.

따라서 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를 사용하는 것이 가장 좋습니다.


이것은 상당히 왜곡 된 주장입니다. range ()는 단순히 반복 생성기를 살펴보고 for 루프에서 사용되는지 또는 색인을 생성하는지 여부는 호출자에게 맡겨야합니다. 사람들은 밀레니아에 대해 루프에서 플로트를 사용하고 있으며 위의 타당성은 무의미합니다. 파이썬위원회의 사람들은 여기에서 큰 시간을 허비했고 좋은 논쟁은 아마도 위와 같은 일부 왜곡 된 정당화에 빠져 익사했을 것입니다. 그것은 평범하고 단순합니다. 파이썬 언어로 위와 같은 결정이 너무 많습니다.
Shital Shah 2

3

NumPy와 등 종속 관계없이 솔루션은 kichik에 의해 제공되었다하지만 인해 부동 소수점를 arithmetics , 종종 예기치 않게 동작합니다. 지적한 바와 같이 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
        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 로도 제공됩니다 .


frange (2.0, 17.0 / 6.0, 1.0 / 6.0)에서는 실패합니다. 견고하게 만들 수있는 방법은 없습니다.
benrg

@benrg 이것을 지적 해 주셔서 감사합니다! 엡실론이 점프에 의존해야한다는 것을 알게되어 알고리즘을 검토하고 문제를 해결했습니다. 이 새 버전은 훨씬 더 강력합니까?
Akseli Palén

2

더 간단한 라이브러리리스 버전

아, 도대체-간단한 라이브러리리스 버전으로 버릴 것이다. 자유롭게 개선하십시오 [*] :

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()생성자가 아닌 목록을 반환합니다. 그러나 그것은 내 필요에 충분했습니다.


당신이 중간에 나쁜 부동 점 순진한 결과에 다음 되돌립니다 정지 + 점프를 추가하여 출력 정지 값이 방법을 포함 할 경우, 시도 frange(0,1.1,0.1)및 더 많은 사람들의 같은 선택에frange(0,1.05,0.1)
alancalvitti

@alancalvitti : "나쁜"부동 소수점에 대한 정의는 무엇입니까? 예, 결과는 훌륭하게 인쇄되지 않을 수 있지만 frange ()는 부동 소수점 표현의 한계 내에서 가장 균등 한 간격 값을 제공합니다. 어떻게 개선하겠습니까?
fearless_fool

좋은 지적, 나는 당신이 그러한 작업에 대한 합리적인 수를 넘어서서 Py가 조립과 같은 느낌을주는 고급 언어에 익숙합니다.
alancalvitti

어셈블리? 허 럼프! :) 물론 파이썬은 정확한 분수와 표현을 제공 할 수 docs.python.org/3/library/fractions.html을
fearless_fool

고마워,하지만 예를 들어, 내가 좋아하는 언어는 이러한 유형을 자동으로 변환하므로 1/2은 합리적이며 1 / 2.0은 부동이므로 선언 할 필요가 없습니다-선언을 Java로 남겨 두십시오. Py보다 낮거나 조립됩니다.
alancalvitti

2

이것은 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 : 여기에서 몇 가지 의견으로 토론을 읽었지만 지금 세 번째 로이 질문으로 돌아간 후에이 정보를 더 읽기 쉬운 위치에 배치해야한다고 생각합니다.


2

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 및 counter 변수 만 :

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이 예상대로 작동합니다. 이러한 상황에서이 기능을 작동 시키려면 다음과 유사한 해킹을 적용해야합니다.

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 장. 반복자, 반복자 및 생성기)에서 채택되었습니다. 범위를 줄이면 작동하지 않습니다. 이전 솔루션과 같이 해킹을 적용해야합니다.

예를 들어이 생성기를 다음과 같이 사용할 수 있습니다.

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

나는 당신이 요점을 가지고 있다고 생각합니다. 당신은 (매우 첫 번째 제외)이 기능의와 함께 갈 수 있는 모든 당신이 그들에 필요한 파이썬 표준 라이브러리입니다.


1

나는 100 분의 1 이상의 소수 자리없이 배정도 부동 소수점 숫자 범위의 튜플을 반환하는 함수를 작성했습니다. 단순히 문자열과 같은 범위 값을 구문 분석하고 초과를 분리하는 문제였습니다. 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

1

용법

# 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.linspace0.1의 10 진수 증분으로 인해 실제로 어려움을 겪고 있으며 증분을 여러 분할로 변환하는 수식의 나누기 순서는 코드가 정확하거나 깨질 수 있습니다.
  • 다른 답변 np.arange은 더 이상 사용되지 않습니다.

의심스러운 경우 위의 네 가지 테스트 사례를 시도하십시오.


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)

Range의 첫 글자는 대문자입니다. 이 이름 지정 방법은 Python의 함수에는 권장되지 않습니다. 원하는 경우 Range를 drange 또는 frange와 같은 것으로 변경할 수 있습니다. "범위"기능은 원하는대로 작동합니다. 여기에서 매뉴얼을 확인할 수 있습니다 [ http://reference.wolfram.com/language/ref/Range.html ].


0

나는 범위의 모든 기능을 실제로 모방하지만 부동 소수점과 정수 모두를 모방하는 매우 간단한 대답이 있다고 생각합니다. 이 솔루션에서는 기본적으로 근사값이 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)

0

물론 반올림 오류가있을 수 있으므로 완벽하지는 않지만 고정밀 성이 필요하지 않은 응용 프로그램에 일반적으로 사용하는 것입니다. 더 정확하게하려면, 인수를 추가하여 반올림 오류 처리 방법을 지정할 수 있습니다. 반올림 함수를 전달하면 확장 가능하게되고 프로그래머가 반올림 오류 처리 방법을 지정할 수 있습니다.

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]

-1

파이썬에서 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

3
매우 나쁜 해결책, 시도 f_range(0.01,0.02,0.001)... arangeNumpy의 가장 실용적인 목적 은 간단하고 안전하며 빠른 솔루션입니다.
Bart

네 말이 맞아 numpy를 사용하면 코드보다 1.8 빠릅니다.
Grigor Kolev

네 말이 맞아 numpy를 사용하면 코드보다 1.8 빠릅니다. 그러나 내가 일하는 시스템은 완전히 닫혀 있습니다. 더 이상 파이썬과 pyserial 만 없습니다.
Grigor Kolev

-2

부정적인 단계, 잘못된 시작, 중지 등과 같은 간단한 경우를 처리하지 않는 몇 가지 답변이 있습니다. 다음은 이러한 경우 중 많은 것을 처리하여 네이티브와 동일한 동작을 올바르게 처리하는 버전입니다 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을 오류로 만듭니다. range . 한 가지 차이점은 네이티브 범위는 위와 달리 인덱싱 가능하고 뒤집을 수있는 객체를 반환한다는 것입니다.

이 코드 와 테스트 사례를 여기서 재생할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.