반응형

프로그래밍 언어에서 인덱스가 0부터 시작해야 하는 이유를 다룬 Dijkstra의 “Why numbering should start at zero” 문서의 내용을 정리해보았습니다. 아직 좀 더 읽어보며 이해해보려고 노력이 필요한 상황이지만  공유해봅니다.



이상한점이 있는 부분을 알려주시면 감사하겠습니다.  



2023. 12. 24 최초작성




2부터 12까지의  11개의 자연수로 구성된 수열을 다음 4가지 방식으로 나타낼 수 있습니다.  이 중 어느 방식이 수열을 나타내기에 좋은 방법인지 살펴봅니다. 

 

a) 2 ≤ i < 13  ( 2이상 13미만 )   13 - 2 = 11 

 

b) 1 < i ≤ 12  ( 1초과 12이하 )   12 - 1  = 11

 

c) 2 ≤ i ≤ 12  ( 2이상 12이하 )    12 - 2  = 10

 

d) 1 < i < 13  ( 1초과 13미만 )   13 - 1  = 12



a와 b 방식은 범위 시작값(하한)과 범위 끝값(상한)의 차이가 실제 수열에 포함된 숫자의 개수와 같다는 장점이 있습니다.  예를 들어 a 방식의 경우 수열 범위 끝값에서 범위 시작값을 빼면 13 - 2이므로 11입니다. 이 값은 2부터 12까지 숫자의 개수인 11개와 같습니다. b 방식도 마찬가지입니다. 



b와 d 방식의 경우엔 범위 시작값이 자연수의 범위를 벗어납니다. ( 자연수는 1부터 시작합니다. )  이 방식은 좋아보이지 않기 때문에 보통 자연수를 시작값으로 하기 위해  a와 c 방식처럼 ≤를 사용하는게 좋습니다. 




범위의 시작값을 포함시키기 위해 ≤을 사용하기로 하고 이제 범위의 끝값을 살펴봅니다.  이제 위 4가지 경우 중 a와 c 방식 중 하나를 선택할 차례입니다. 

 

a) 2 ≤ i < 13  ( 2이상 13미만 )   13 - 2 = 11 

c) 2 ≤ i ≤ 12  ( 2이상 12이하 )    12 - 2  = 10



가장 작은 자연수에서(일단 1을 의미합니다) 시작하는 수열을 고려해봅니다.  원소가 하나도 없는 비어있는 수열을 표현시  c 방식처럼 범위 끝값을 포함시키기 위해  ≤를 사용하는 것은 어색합니다. 왜냐하면 다음처럼 비어있는 수열을 나타낼 수 없습니다. 

c) 1 ≤ i ≤ 1    

 

따라서 범위의 끝값은 포함시키지 않기 위해 a 방식처럼 <를 사용해야 합니다. 

a) 1 ≤ i < 1

 

이 경우 i가 1 이상이면서 동시에 1 미만인 이러한 조건을 만족하는 정수 i는 존재하지 않기 때문에 이 표현은 어떤 정수도 포함하지 않는 비어있는 수열을 나타냅니다. 




앞에서 두가지 검토한것을 종합해보면 수열을 나타낼때 우린 a방식을 선택해야 합니다.

  1. 2 ≤ i < 13 



다시 정리하면 자연수 수열을 나타낼 경우 j <= i < k로 적어야 합니다. 

 

범위의 시작값(하안)의 경우 j < i 대신에 j <= i를 사용해야 합니다. 왜냐하면 가장 작은 자연수부터 수열이 시작해야 하기 때문입니다. 가장 작은 자연수보다 작은 뭔가를 추가하는 것은 어색하며 불가능합니다. 따라서 하안에 가장 작은 자연수를 포함시켜야 하므로 < 대신에 <=를 사용해야 합니다. 

 

범위의 끝값(상한)은 k <= i 대신에  k < i 를 사용해야 합니다. 비어있는 수열을 고려해보면 k <= i < k는 비어있는 수열이지만 k <= i <= k는 비어있는 수열이 아니기 때문입니다. 



a 방식 사용시 또다른 장점은 두 개의 수열을 연결하기 쉽습니다.

예들 들어 z <= i < y로 나타내지는 수열과  y <= i < x로 나타내지는 수열을 하나로 연결하면  z <= i < y 가 됩니다. 두 개의 수열을 연결 후에도 똑같은 방식으로 표기되네요.  다시 보면 수열의 범위 끝값과 다른 수열의 범위 시작값이 같습니다. 



지금까지 범위의 시작값과 범위의 끝값을 범위에 포함시킬지 여부를 살펴보았습니다. 

 

이제 길이가 N인 수열을 다룰 때, 인덱스를 사용하여 수열의 숫자를 가리킨다고 봅시다. 그럼 인덱스의 시작값으로 어떤 값을 사용해야 할까요. 

인덱스가 1부터 시작하면 인덱스의 범위는 1 ≤ i < N+1이 되고,  인덱스가 0부터 시작하면 0 ≤ i < N이 됩니다. 직관적으로 N개의 자연수로 구성된다는 것을 인식하기에는 인덱스가 0부터 시작하는 것이 좋습니다. 왜냐하면 원소의 인덱스는 수열에서 그 앞에 있는 원소의 개수와 같습니다.   



앞에서 수열을 자연수 범위로 하기 위해  범위 시작값을  자연수로 하기 위해  < 대신에 <=를 사용해야 한다고 해놓고 이제와서 자연수가 아닌 0을 범위 시작값에 포함시켜야 한다는게 이해되지 않네요. 

 

다시 원문을 다시 보니 결론은 자연수에 0을 포함시켜야 한다는 거네요. 

 And the moral of the story is that we had better regard —after all those centuries!— zero as a most natural number.



주의 할점은 수열에 포함된 숫자의 개수를 세는 것과 인덱싱하는 것에는 차이가 있습니다.

 

                1, 2, 3, 4, 5

 

인덱스       0  1  2  3  4

숫자개수    1  2  3  4  5



인덱스가 0부터 시작해야 하는 이유중 하나는 메모리 때문입니다. 예를 들어 메모리에 배열을 저장시 인덱스는 배열의 시작위치를 가리켜야 합니다.  왜냐하면 배열의 첫번째 원소의 위치는 시작 주소로부터의 오프셋이 0이기 때문에 당연히 인덱스가 0이 되는게 자연스럽습니다.  




다음은 쳇지피티를 사용하여 조사한 결과입니다.



인덱스가 0부터 시작하는 프로그래밍 언어들이 대부분이며, 이러한 디자인 결정은 주로 컴퓨터 과학의 기본 원리와 메모리 관리의 효율성과 관련이 있습니다. 여기 몇 가지 대표적인 언어와 그 이유를 소개합니다: 여기에 언급된 언어는 C언어의 영향 때문이네요.

 

1. C 언어: 인덱스가 0부터 시작하는 가장 대표적인 언어 중 하나입니다. C 언어에서 배열의 이름은 배열의 첫 번째 요소를 가리키는 포인터로 사용됩니다. 따라서, 배열의 첫 번째 요소는 0번째 인덱스를 가지게 됩니다. 이러한 설계는 메모리 주소 계산을 단순화하고, 포인터 산술을 직관적으로 만듭니다.

 

2. Java: Java도 C 언어의 영향을 받아 0부터 인덱싱을 시작합니다. Java는 C와 같은 방식으로 배열을 처리합니다. 이는 메모리 주소 계산의 일관성과 효율성을 위한 선택입니다.

 

3. Python: Python 역시 0부터 인덱싱을 시작합니다. Python에서 이러한 방식은 C 언어의 배열 관리 방식을 따르는 것이며, 컴퓨터 메모리와 가까운 낮은 수준의 데이터 구조를 효율적으로 처리하기 위함입니다.

 

4. JavaScript: 웹 개발에 널리 사용되는 JavaScript도 0부터 시작하는 인덱싱을 사용합니다. 이는 초기 웹 개발에서 C언어의 영향을 받은 결과입니다.

 

이러한 언어들에서 0부터 시작하는 인덱스를 사용하는 주된 이유는 컴퓨터 메모리의 주소 체계와 밀접하게 관련이 있습니다. 컴퓨터 메모리는 주소로 데이터를 저장하고 접근하며, 배열의 첫 번째 요소가 시작 주소에 위치하기 때문에 0부터 시작하는 인덱싱이 메모리 주소 계산을 단순하고 효율적으로 만듭니다. 이는 포인터 산술을 쉽게 하고, 전반적인 프로그래밍의 효율성과 일관성을 증가시킵니다.




인덱스가 1부터 시작하는 프로그래밍 언어는 상대적으로 적으며 이들은 주로 수학적 편의성, 역사적 이유, 또는 디자인 철학 때문에 이러한 선택을 했습니다. 

 

1. Fortran: 과학 및 공학 계산을 위해 1950년대에 개발된 Fortran은 배열 인덱싱을 1부터 시작합니다. 이는 수학적 표현과의 밀접한 연관 때문일 수 있습니다. 과학자와 엔지니어들은 전통적으로 1부터 수를 세는 것에 익숙하기 때문에, Fortran은 이러한 관행을 반영합니다.

 

2. MATLAB: 공학 및 수학 분야에서 널리 사용되는 MATLAB 역시 1부터 인덱싱을 시작합니다. 이는 Fortran의 영향을 받았을 수 있으며, 행렬 기반 계산에서 1부터 시작하는 것이 더 직관적일 수 있습니다.

 

3. Lua: 게임 개발 및 임베디드 시스템에서 사용되는 Lua 프로그래밍 언어도 1부터 인덱싱을 시작합니다. 이는 Lua의 디자인 철학과 관련이 있으며, 사용자 친화적인 언어 구조를 제공하기 위한 선택으로 보입니다.

 

4. R: 통계 계산과 그래픽을 위한 언어인 R도 1부터 시작하는 인덱스를 사용합니다. 이는 통계학에서의 전통적인 수학적 표현을 반영하는 것일 수 있습니다.

 

이러한 언어들에서 1부터 시작하는 인덱스를 사용하는 이유는 주로 해당 언어의 사용 사례와 타깃 사용자 그룹에 기반을 두고 있습니다. 과학, 공학, 통계학 등의 분야에서는 전통적으로 1부터 수를 세는 것이 보편적이므로, 이러한 분야를 위해 설계된 언어들은 이러한 관행을 반영하는 경향이 있습니다.





https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html?fbclid=IwAR0CN13rw8tsEOOa9D7ZVmaQRUTfpT6MmJz70NoNLPasWdZ6F_CPBsdHAnM_aem_AYQpjubPMUJkRJm3V5M-psyU5k3aNTdtlJrd-jpKhoEzgwVUvunalQl1fl7QXAv3LDA

 

https://www.reddit.com/r/ProgrammingLanguages/comments/maft1w/dijkstras_why_numbering_should_start_at_zero/

 

https://www.reddit.com/r/programming/comments/elr06/dijkstra_why_numbering_should_start_at_zero/




반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts