표준 라이브러리에 부동 소수점 범위 구현이없는 이유는 무엇입니까?
여기의 모든 게시물에서 알 수 있듯이의 부동 소수점 버전은 없습니다 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를 사용하는 것이 가장 좋습니다.