source

플로트에 대한 범위(범위)

nicesource 2023. 6. 18. 16:07
반응형

플로트에 대한 범위(범위)

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

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

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

또는 람다 / 지도 사용:

map(lambda x: x/10.0, range(5, 50, 15))
내장된 기능은 잘 모르지만, [이렇게](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▁the로서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

[문제는 그렇지 않습니다: 만약 당신이 긍정적인 것만을 사용한다면.jumpstop (으)로 표시됩니다.x그리고.y), 이것은 잘 작동합니다.보다 일반적인 솔루션은 여기를 참조하십시오.]

사용한 적이 있습니다.numpy.arange그러나 부동 소수점 오류로 인해 반환되는 요소의 수를 제어하는 데 약간의 문제가 있었습니다.은 그서이제를 사용합니다.linspace항목:

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

필라브하스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. ])

평가함 ( 열심평됨가히(2.x))range):

[x * .5 for x in range(10)]

평가 .x 게평됨가르으(2.x))xrange 3.xrange):

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.

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

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

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)

이러한 기본 제공 기능은 없지만 다음(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에서 사용 가능한 코드

키치크가 썼듯이, 이것은 너무 복잡하지 않을 것입니다.그러나 이 코드는 다음과 같습니다.

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

중첩 함수가 없습니다.잠시 및 카운터 변수:

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

물론 플로트인트에도 사용할 수 있습니다.

조심하세요.

음의 단계에서 이러한 기능을 사용하려면 다음과 같은 단계 기호에 대한 확인을 추가해야 합니다.

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

당신 말이 맞는 것 같아요.당신은 이러한 모든 기능(첫 번째 기능 제외)과 함께 사용할 수 있으며 필요한 것은 파이썬 표준 라이브러리입니다.

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

있는 알 수 , 여기있는모게든분서알명수있이듯, ▁of▁version▁as의 버전은 없습니다.range()그렇긴 하지만, 만약 우리가 고려한다면, 누락은 말이 됩니다.range()함수는 인덱스 생성기(물론, 액세스를 의미함)로 자주 사용됩니다.그래서 우리가 전화할 때.range(0,40)우리는 사실상 40개의 값을 0에서 시작하여 최대 40개까지 원한다고 말하고 있지만, 40개 자체가 아닌 값을 원합니다.

할 때, float의 은 float의 값입니다.range()표준 라이브러리에서는 말이 안 됩니다.를 들어,가 함수를 들어를라고 , 호를출한경라고 불렀을 입니다.frange(0, 10, 0.25)되지만, 그렇게 우는과 0이 10두모 포개예것, 리그 41이를산것, 것은예 40닙다에서 기대할 수 있는 값을 됩니다.10/0.25.

그, 따서용, 에따도라그,frange()함수는 항상 반대의 직관적인 동작을 나타냅니다. 인덱싱 관점에서 인식된 값이 너무 많거나 수학적 관점에서 합리적으로 반환되어야 하는 숫자를 포함하지 않습니다.가 매우 두 사용 사례를 알 수. 즉, 사례를 사용 를 의미합니다. ", 이한함가매우다즉혼른어게떻쉽지는동두알하수인있게의가례사사수사동명사의덱싱미용하미고은를합례작학적니다를례용은명즉다습니수러를지용사사▁in▁would▁it▁very▁function▁implies즉▁cases사사수▁–의▁how동▁a▁use의미용를합▁other▁the▁to▁such▁the례적,니은다학작▁implies▁case

수학적 활용 사례

때문에 글에서 처럼, 말과함께논다게, 바의같와이된서에물시,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는 개변 수는다수분없다습니로 할 수 .stopvalue,문제를 할 때 큰 수 : 후, 자의문고때할려큰있차수있다니값습을가.

# 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를 사용하는 것이 가장 좋은 방법일 것입니다.

키치크는 numpy의존성이 없는 솔루션을 제공했지만 부동소수점 산술로 인해 종종 예기치 않게 동작합니다.저와 bubberdiblub지적한 바와 같이, 추가적인 요소들이 결과에 쉽게 잠입합니다.예를들면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로도 사용할 수 있습니다.

라이브러리가 없는 단순한 버전

아, 이런 -- 간단한 라이브러리가 없는 버전으로 하겠습니다.언제든지 개선하십시오[*]:

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...nstep]을 [start]에 선형으로 매핑하는 것입니다.정지]

편집을

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()생성기가 아닌 목록을 반환합니다.하지만 그것은 제가 필요로 하는 것으로 충분했습니다.

numpy.range(시작, 중지, 단계 크기)를 사용하여 수행할 수 있습니다.

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:에서 "로 여기댓섹글절토션론서에함안의 "사용대사 절안함▁from용"를 사용하지 마세요numpy.arange()(넘피 문서 자체가 권장하지 않음).wim이한 대로 "wim 추로천 numpy.linspace"라는 대답의 다른 제안 중 합니다.

참고 2:저는 여기서 몇 가지 의견으로 토론을 읽었지만, 이제 세 번째로 이 질문으로 돌아와서 이 정보를 좀 더 읽기 쉬운 위치에 두어야 한다고 생각합니다.

사용.

# 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

왜 이 답을 선택해야 합니까?

  • 카운트다운을 요청하면 다른 많은 답변이 표시됩니다.
  • 다른 많은 답변은 잘못된 반올림 결과를 제공합니다.
  • ▁on▁based에 기초한 다른 np.linspace정확한 분할 수 선택의 어려움으로 인해 작동하지 않거나 작동하지 않을 수 있습니다. np.linspace하며, 할 수 . 0.1 소수증씨름하며과분공, 증여분분식의순변할정는서는수환확거하있하손다나분할초니상코된습드할래를로러을의점▁really0▁code▁to▁in▁formula▁incre다있수니▁result습▁in▁either▁the▁struggles▁broken▁with할초▁and▁decimal손▁or▁the▁can래코나된상를드ments▁0▁of정거하확▁of▁correct▁increment▁convert▁divisions▁order▁into순▁the는서분할증분
  • ▁on▁based에 기초한 다른 np.arange사용되지 않습니다.

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

질문이 오래된 것인지는 모르겠지만 다음과 같은 것이 있습니다.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])

저는 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. 지정된 범위를 특정 세그먼트 수로 분할: 범위를 잘 분할하지 않는 포인트 수를 선택할 때 큰 소수 자릿수를 허용하는 린스페이스 접근 방식(예: 7단계에서 0 - 1은 첫 번째 단계 값 0.14285714285)

  2. 원하는 WYSIWIG 스텝 크기를 지정합니다. WYSIWIG 스텝 크기는 이미 작동해야 하며 작동하기를 희망합니다.여러분의 희망은 종종 여러분이 치고 싶었던 종점을 놓친 값들을 얻음으로써 깨질 것입니다.

배수는 예상보다 높거나 낮을 수 있습니다.

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

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

여러분은 실수가 누적되는 것을 피하려고 노력할 것입니다. 여러분의 단계의 배수를 더함으로써 증가하지 않고, 하지만 문제는 항상 그 자체로 나타날 것이고, 여러분이 종이 위에서 손으로 그것을 했다면 여러분이 기대했던 것을, 정확한 소수로 얻을 수 없을 것입니다.하지만 파이썬이 당신에게 보여주기 때문에 가능해야 한다는 것을 알고 있습니다.0.10에 근사값을 기본 비율 .1에 가까운 근사값을 갖는 기본 정수 비율 대신:

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

답변으로 제공되는 방법에서는 입력을 문자열로 처리하는 옵션과 함께 분수를 사용하는 것이 가장 좋습니다.이를 개선하기 위해 몇 가지 제안이 있습니다.

  1. 범위와 같은 기본값을 처리하여 0부터 자동으로 시작할 수 있도록 합니다.
  2. 감소하는 범위를 처리하도록 합니다.
  3. 정확한 산술 연산을 사용하는 경우 출력을 예상되는 것처럼 만듭니다.

저는 이러한 종류의 작업을 수행하지만 Fraction 객체를 사용하지 않는 루틴을 제공합니다.대신에, 그것은 사용합니다.round파이썬으로 인쇄할 경우 숫자와 동일한 겉보기 숫자를 가진 숫자를 만들려면, 예를 들어 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)
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)

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

플로트와 정수를 제외한 범위의 모든 특징을 실제로 모방한 아주 간단한 답이 있다고 생각합니다.이 솔루션에서는 기본적으로 근사치가 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)

두더지 언덕으로 산을 만드는 것에 대해 이야기해 보세요.만약 당신이 요구사항을 완화시킨다면, 플로트 아날로그를 만들 것입니다.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.]])]

물론 약간의 반올림 오류가 있을 것이기 때문에 완벽하지는 않지만, 이것은 높은 정밀도를 요구하지 않는 애플리케이션에 일반적으로 사용하는 것입니다.이 값을 더 정확하게 지정하려면 인수를 추가하여 반올림 오류를 처리하는 방법을 지정할 수 있습니다.반올림 함수를 전달하면 이것을 확장할 수 있고 프로그래머가 반올림 오류를 처리하는 방법을 지정할 수 있습니다.

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]

파이썬에서 플로트에 해당하는 범위()가 있습니까?사용 안 함:

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

여기에는 네거티브 스텝, 잘못된 시작, 중지 등과 같은 단순한 에지 사례를 처리하지 않는 몇 가지 답변이 있습니다.네이티브와 동일한 동작을 제공하는 이러한 사례의 대부분을 올바르게 처리하는 버전은 다음과 같습니다.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합니다. step=0도 오류가 발생합니다.range한 가지 차이점은 네이티브 범위가 인덱스 가능하고 되돌릴 수 있는 개체를 반환하지만 위에서는 그렇지 않다는 것입니다.

당신은 여기서 이 코드와 테스트 케이스를 가지고 놀 수 있습니다.

언급URL : https://stackoverflow.com/questions/7267226/range-for-floats

반응형