왜 인덱스는 0에서 시작해야 하는가?
위대하신 다익스트라님의 포스트를 번역해보았다.
자연수의 시퀀스 2, 3, ..., 12
를 ...
없이 표현하기 위해서, 네 가지
방법이 가능하다.
- \[2 \leq i < 13\]
- \[1 < i \leq 12\]
- \[2 \leq i \leq 12\]
- \[1 < i < 13\]
특정 방법을 선호해야 할 이유가 있을까? 그렇다. 있다. 1번과 2번의 경우 끝 범위와 시작 범위의 차이가 곧 시퀀스의 길이와 같다는 장점이 있다. 결과적으로 두 개의 시퀀스가 인접한다는 장점도 있다. 즉, 한 시퀀스의 상한(Upper Bound)이 다른 시퀀스의 하한(Lower Bound)와 같다. 이런 관찰은 유효하지만, 1번과 2번 둘 중 뭘 선택해야 할지는 여전히 어렵다. 그러니 새롭게 시작해보자.
자연수에는 가장 작은 수가 있다. 2번과 4번처럼 하한을 제외하면 가장
작은 자연수에서 시작하는 시퀀스의 하한이 자연수 범위 바깥을
벗어나도록 강제된다. 이건 아름답지 못하기 때문에, 하한은 1과 3처럼 \(\leq\)이 선호된다. 이제 가장 작은 수에서 시작하는 시퀀스를
생각해보자. 상한을 포함하면, 이 시퀀스가 나중에 빈 시퀀스로 수렴할 때
부자연스럽게 된다. 예를 들어, \(0 \leq x \leq 3\) 이 \(0 \leq x
\leq -1\)이 된다. 이것도 아름답지 못하기 때문에, 상한은 1과 4처럼
<
이 선호된다. 이를 통해 빈 시퀀스를 \(0 \leq x < 0\) 으로 표현할
수 있게 된다. 결론적으로 1이 선호된다.
참고로, 제록스 PARC에서 개발된 프로그래밍 언어 Mesa는 정수의 범위를 표현하기 위해서 네 가지 방법 모두를 위한 특별한 표현이 있다. Mesa와 관련한 대규모 실험에 따르면 1을 제외한 나머지 세 개의 방법은 끊임없이 어색함과 실수의 원인이 되어왔기 때문에, Mesa 프로그래머들은 이 세 방법을 사용하지 않는 것을 강하게 권장한다고 한다.
다음 질문은 길이 N
의 시퀀스를 다룰 때, 시작 원소로 어떤 값을
택할지이다. 1번 방법을 준수한다고 치고, 1부터 시작하게 되면 범위는 \(1 \leq i < N + 1\)이 된다. 반면, 0부터 시작하게 되면 좀더 괜찮은
범위인 \(0 \leq i < N\)이 된다. 따라서 범위는 0부터 시작하도록
하자. 이렇게하면 원소의 인덱스는 시퀀스에서 해당 원소 앞의 원소의
개수와 같다. 그리고 이 이야기의 교훈은, 수많은 시간이 지난 후에야
비로소 우리는 0을 가장 자연스러운 숫자로 간주하는 것이 더 낫다는
것이다.
참고로, 많은 프로그래밍 언어는 이런 디테일을 놓친 채로 디자인되어 있다. 포트란의 인덱스는 항상 1로 시작한다. 알골 60과 파스칼에서는 3번 방법이 적용되었다. 그나마 최근의 SASL에서는 다시 포트란으로 돌아가버렸다. 저런.
위와 같은 글을 작성하게 된 이유는 최근에 대학의 (CS가 아닌) 수학과 동료와 이야기하다가, 그가 어린 CS 학도들이 “숫자를 0부터 시작하는 것에 지나치게 집착한다”고 불만한 것을 듣고 감정적으로 격해졌기 때문이다. 그는 가장 합리적인 관습을 의식적으로 도발로 받아들였다. 나는 Antony Jay가 다음과 같이 말한 것이 옳다고 생각한다:
다른 종교와 마찬가지로, 이단자는 그가 틀렸을 가능성 때문이 아니라 그가 옳을 가능성 때문에 추방되어야 한다.
참고로 이 글은 1982년, 그러니까 대략 40년 전의 글이다. 그때는 다익스트라가 이런 글을 쓸 정도로, 0부터 인덱스를 세는 것이 메인스트림이 아니었나보다. 지금와서는 대부분의 언어가 다 0부터 인덱스를 세고 있고 되려 1-인덱스가 드문 편이니 참으로 격세지감. 찾아보니 놀랍게도 나름 최신 언어인 줄리아가 1-인덱스인 것 같은데, R이나 매스매티카와 비슷하게 줄리아도 계산과학에 치중한 언어라서 Matrix 연산을 자유롭게 표현하기 위함인 것 같다.
그리고 한번도 생각해본적 없었는데 0-인덱스와 하한포함-상한제외 범위를
쓰면 인덱스 = 해당 원소 앞까지의 개수
가 성립한다는 점도 흥미로웠다.