범위
범위 (Ranges)
범위(range)는 요소들이 균등한 간격으로 배치된 행 벡터를 간편하게 쓰는 방법이에요. 범위 표현식은 범위의 첫 요소 값, 요소 사이의 증가분(선택), 그리고 범위의 요소들이 넘지 못할 최댓값으로 정의됩니다. 기준값(base)과 증가분(increment), 한계(limit)는 콜론(:)으로 구분하고, 여기에는 어떤 산술 표현식이나 함수 호출도 넣을 수 있어요. 증가분을 생략하면 1로 간주합니다.
출처: Ranges
본문
예를 들어 범위
1 : 5
는 값 집합 [ 1, 2, 3, 4, 5 ]를 정의하고, 범위
1 : 3 : 5
는 값 집합 [ 1, 4 ]를 정의해요.
범위 상수는 행 벡터를 지정하지만, Octave는 꼭 필요할 때가 아니면 보통 범위 상수를 벡터로 변환하지 않습니다. 그래서 1 : 10000 같은 상수를 일반 워크스테이션에서 80,000바이트를 쓰지 않고도 적을 수 있어요.
범위를 벡터로 변환해야 하는 흔한 경우는 범위가 벡터 안(즉 대괄호 안)에 나타날 때입니다. 예를 들어
x = 0 : 0.1 : 1;
은 x를 double_range 타입으로 정의하며 24바이트 메모리를 차지하지만,
y = [ 0 : 0.1 : 1];
는 y를 matrix 타입으로 정의하며 88바이트 메모리를 차지해요.
이런 공간 절약 최적화는 optimize_range 함수로 끌 수 있습니다.
val =optimize_range()¶old_val =optimize_range(new_val)¶old_val =optimize_range(new_val, "local")¶ — 범위를 저장할 때 특별한 공간 효율 형식을 쓰는지 조회하거나 설정합니다.
기본값은 true예요. 이 옵션을 false로 설정하면 Octave는 범위를 전체 행렬로 저장합니다. 함수 안에서 "local" 옵션과 함께 호출하면 그 설정이 함수와 호출하는 서브루틴에만 로컬로 적용되고, 함수를 빠져나오면 원래 설정으로 복원돼요.
참고: optimize_diagonal_matrix, optimize_permutation_matrix.
범위의 위쪽(증가분이 음수면 아래쪽) 경계가 항상 값 집합에 포함되는 것은 아니라는 점을 알아 두면 좋아요. 어떤 상황에서는 이 성질이 유용합니다. 예:
## x is some predefined range or vector or matrix or array
x(1:2:end) += 1; # increment all odd-numbered elements
x(2:2:end) -= 1; # decrement all even-numbered elements
위 코드는 x의 요소 수가 홀수인지 짝수인지에 관계없이 올바르게 동작해요. 두 경우를 다르게 처리할 필요가 없지요.
Octave는 범위의 값을 계산할 때 부동소수점 연산을 사용합니다. 그래서 부동소수점 값으로 범위를 정의하면 이런 함정이 생길 수 있어요.
a = -2
b = (0.3 - 0.2 - 0.1)
x = a : b
부동소수점 반올림 때문에 b는 정확히 0과 같을 수도, 아닐 수도 있고, 0보다 크거나 작을 수도 있어요. 그래서 최종 범위 x가 마지막 값으로 0을 포함할 수도, 포함하지 않을 수도 있습니다. 마찬가지로
x = 1.80 : 0.05 : 1.90
y = 1.85 : 0.05 : 1.90
는 보기처럼 예측 가능하지 않아요. Octave 8.3 기준 결과를 보면 x는 세 요소(1.80, 1.85, 1.90)를 갖고, y는 한 요소(1.85, 1.90이 아님)만 가집니다. 즉 범위에서 부동소수점을 쓸 때 시작점을 바꾸면, 위 예에서 끝값을 건드리지 않았는데도 끝값에 쉽게 영향을 줄 수 있어요.
이런 함정을 피하려면 다음 패턴 중 하나를 쓰면 됩니다. 위 코드를 이렇게 바꾸면
x = (0:2) * 0.05 + 1.80
y = (0:1) * 0.05 + 1.85
정수로 범위를 만들고 나서 부동소수점으로 변환하므로 전체 표현식이 안전하고 플랫폼·컴파일러·컴파일러 설정에 관계없이 반복 가능해요. 요소 수를 안다면 linspace 함수(Special Utility Matrices 참고)를 쓰면 범위의 끝점을 포함합니다. round, floor, ceil, fix 등을 적절히 써서 한계와 증가분을 정하는 방법도 있어요. 예를 들어 앞선 예는 다음 중 하나로 더 안전하게 만들 수 있습니다.
a = -2
b = round ((0.3 - 0.2 - 0.1) * 1e12) / 1e12 # rounds to 12 digits
c = floor (0.3 - 0.2 - 0.1) # floors as integer
d = floor ((0.3 - 0.2 - 0.1) * 1e12) / 1e12 # floors at 12 digits
x = a : b
y = a : c
z = a : d
범위 표현식의 결과가 비어 있으면 Octave는 빈 matrix를 돌려주고, 빈 double_range를 돌려주지 않아요. 마찬가지로 범위에 요소가 하나뿐이면 scalar를 돌려주고, 요소 하나짜리 double_range를 돌려주지 않습니다.