[OS]컴파일 & 링킹 & 로더 과정

리버싱 2017. 2. 8. 16:45

소스코드가 어떻게 컴파일 되고 링킹 되는지 그 과정을 알아 보겠습니다.

OVERVIEW

프로그램이 빌드되는 과정



  • 각각 의 소스파일들이 .O (오브젝트 파일로) 변환이 되고
  • 여러개의 오브젝트 파일이 하나의 오브젝트 파일로 묶이는데 이것을 Linker라고 한다.
  • 이렇게 하나의 오브젝트파일로 묶인 파일을 Executable File 이라고 한다.
  • 이렇게 생긴 exe 파일을 실행시키면 OS의 로더에 의해서 메모리에 깔리게 되고
  • 그 프로세스들에게 필요한 Context들이 생겨나면서 프로그램이 수행 가능하게 된다.

소스 파일

  • 사람이 읽을 수 있는 문법들 (C , JAVA)

오브젝트 파일

  • 수행 코드, 데이터 들이 저장되어 있다.
  • 또 이런 수행코드, 데이터들이 메모리 어디에 저장되어야 하는지 알려주는 주소 정보들이 있다.
  • 그리고 여러 변수들의 정보 등등..이 저장되어있는 Symbol Table이 있다.
  • Linker가 프로그램을 Linking 하기 위해 사용하는 정보가 있는데 그 정보들이 저장된 테이블을 Relocation Table 이라 한다.

컴파일러

  • 각 소스파일을 오브젝트파일로 변환 시켜주는 역할을 한다.

링커

  • 모든 오브젝트 파일들을 하나의 오브젝트 파일로 합친다(Executable file로 합친다)

로더

  • Executable file 을 읽는다.
  • 메인 메모리에 오브젝트 파일에있는 내용들을 올리고
  • context들을 만들고 프로그램을 수행시킬 수 있도록 만든다.
  • OS의 한 부분이다.

Section

  • 컴파일러를 거쳐 만들어진 오브젝트 파일 안에는 여러개의 Section이 존재한다.
  • 오브젝트 파일을 구성하는 Unit 들 또는 어떠한 데이터를 묶어놓은 단위들을 Section 이라 한다.
  • 각 섹션들은 추후 메모리에 적재될 독자적인 영역을 가지게 된다. -> 이 영역을 세그먼트라고 부른다.
  • 각 섹션안에는 함수이름이나, 변수이름등 , 여러 심볼들이 존재하고 그 섹셕안에서 자신만의 위치인 offset을 주소로 가진다.

오브젝트 파일을 구성하는 Section 들

  • Text section(Code section) : 명령어들이 들어가 있다.(ex: printf(“hello); )
  • Data section : 초기화 된 전역 변수, static 변수 들이 저장되어 있다.(ex: int a = 0;)
  • BSS section : 초기화 되지 않은 전역 변수, static 변수 들이 저장되어 있다.(ex: int b;) -> BSS:Block Started by Symbol
  • Stack section : 지역 변수, 매개 변수 들이 저장됨, 함수 호출시 생성되고 함수 종료시 시스템에 반환
  • Ohter section : Relocation table , Sybol table 등이 저장됨

왜 BSS 와 Data 섹션을 구분 하였을까?

  • 변수 선언을 하고 값을 넣어 초기화를 하면 메모리에 그만큼의 공간을 잡아 먹는다(ex:int a = 4; 는 4바이트 공간을잡음)
  • 그런데 만약 int a[100000] 과 같은 배열을 선언만하고 초기화 하지 않았다고 하자 400000 바이트의 공간을 쓸데 없이 잡아먹을 필요가 없기 때문에 그냥 저 변수의 이름과 얼마만큼 크기를 잡았다는 정보만 올려주기 위해 BSS 와 Data 섹션을 구분지어서 사용한다.

.c 파일이 컴파일 되는 과정


  • .c 파일이 컴파일러를 통해 .o 파일로 변환되는 과정
  • 소스코드들이 각 섹션으로 배치된다.

.o 파일들을 링킹 하는 과정



  • 여러 오브젝트 파일에있는 동일한 섹션들을 하나의 덩어리로 합친다.
  • 이때 각 섹션들을 몇 번지에 저장하라고 하는 별도의 파일이 있는데 이것을 링커 스크립트 파일이라고 한다.
  • 예를 들어 특정 하드웨어(임베디드 시스템)의 메모리 앞부분 1mb 가 ROM이라고 하면 이 부분 다음부터 섹션을 적재 시켜야 하므로 링커 스크립트 파일을 이용하여 설정해줄 수 있다.
  • 링킹이 끝나면 Executable File이 생성된다.

Loader 가 Exe파일을 읽어들이는 과정

  • OS Loader가 exe파일을 읽는다.
  • 이미 exe 파일에는 Data section은 몇번지에 저장하고, Code section은 몇번지에 저장하라는 정보들이 다 들어있기 때문에 그대로 읽어 오면 된다.
  • 그리고 마지막으로 PC(Program Counter)를 그 exe파일의 엔트리 포인트로 설정하면 로딩이 끝난다.

링킹 과정의 문제점

  • 우리가 소스코드로 코딩할때는 우리가 읽을 수 있는 문자,부호 들을 사용하지만 실제 컴퓨터가 읽을때는 010101 로 읽는다.
  • 결국 실제로 마이크로프로세서는 문자들을 읽는것이 아니라 이것의 OP코드와 , 오퍼랜드의 주소, 등을 본다.
  • 즉 다시말해서 우리가 입력한 Symbol(문자,부호)들을 주소로 변환 하여야 한다.
  • 그런데 Symbol 이 주소로 변환되려면 이 Symbol이 실제 어느 위치에 있는지 알아야 하는데 이 위치를 안다는 것은 쉬운 일이 아니다.
  • C는 소스 파일이 여러개로 쪼개져 있고 링킹 하기 전에 오브젝트 파일도 여러개로 쪼개져 있기 때문에 컴파일러가 한 오브젝트 파일을 만지고 있는 동안 다른 오브젝트 파일의 Symbol 주소를 알 수가 없다. 이것을 Cross-reference라고 한다.
  • 이 Cross-refernce를 해결하는 것이 링커의 몫이다.

Cross-refernce 해결 방법

  • Cross-refernce 에 대한 정보가 여러 오브젝트 파일에 흩어져 있으므로 각 오브젝트 파일을 다니면서 주소들을 수집해야 한다.
  • 그리고 나서 수집된 주소들을 이용해서 실제 주소들로 대체한다.
  • 링커가 이 문제를 해결하려면 path를 2개 이상 사용해야 링킹을 할 수 있다.

Symbol Table



  • Symbol들의 주소와 정보들을 쉽게 찾을 수 있도록 한곳에 모아 둔 테이블이다.
  • 위 그림과 같이 코드를 변환 하는 작업이 필요한데 이때 Symbol Table을 사용한다.



  • Symbol Table의 정보를 검색할때는 Symbol의 이름으로 검색 한다.
  • 테이블에는 각 심볼이 포함된 Section의 시작 주소와 그 심볼의 Section내 offset이 기입되어 있다.
  • 정리하자면 컴파일러가 어떤 심볼을 읽게 되면 그 심볼에 해당하는 진입점을 테이블에 넣고 그 심볼의 주소를 알 수 있으면 Section 주소와 offset으로 채워 넣는다. 이러한 주소를 Internal Reference 라고 한다.
  • 이때 주소를 알 수 있다는 것은 자신과 같은 오브젝트 파일을 생성 할때 알 수 있다는 말이다.

Relocation Table(1)

  • Section 시작주소 + offset 주소로 파악된 symbol 주소(Internal Reference)를 PC Relative 한 주소로 변환한다. 즉 PC 상대주소로 변환한다.
  • 이런 변환을 하는 이유는 전체 section의 위치가 변경 되어도 PC로부터의 상대적인 주소(거리)는 바뀌지 않기 때문이다.
  • 그래서 PC Relative 한 주소로 변환하여 사용한다.
  • ex) call local_func -> call PC+0x1B

Relocation Table(2)

  • 그럼 Cross reference 들은 어떻게 처리 할까?
  • 링커가 Cross reference 들의 주소를 모르기 때문에 모른다고 체크(0으로 채운다)해놓고 Internal Reference 를 우선적으로 처리한다.
  • ex) call printf -> call 0x0
  • 추가적으로 Relocation Table에 이 Cross reference의 위치를 기입한다.

Relocation Table Example(1)



※ c언어의 extern 키워드는 해당 변수가 외부의 다른 파일에서 정의 되었다는것을 알려주는 것이다.

  • 컴파일을 하면 맞는 섹션에 소스코드가 적재가 되고 오브젝트 파일들이 만들어진다.
  • my_var, func() 둘다 Cross Reference 이므로 정확한 주소를 몰라 일단 0x0 으로 초기화한다.
  • 그런 후 Text 섹션의 시작위치와 mov, call의 명령어의 섹션내 offset을 Relocation Table에 적재 시킨다.
  • 링커의 첫번째 path 에서 이러한 과정으로 Relocation Table을 생성한다.



  • 링커 스크립트에 의해 섹션들이 합병되면 각 작은 섹션들의 위치를 알 수 있고
  • 마찬가지로 그 작은 섹션 안에 있는 Symbol 들의 주소 정보들역시 파악할 수 있어 Symbol Table 에 적재 시켜 놓는다.
  • 이전에 Relocation Table에 적재 시켰던 Symbol Name 을 가지고 Symbol Table 에 가서 그 Symbol의 메모리 주소를 찾아 가져와서 고친다.

Relocation Table Example(2)



  • 소스코드가 2개의 .c 파일로 되어있다.
  • 우선 main.c 를 컴파일 하면 아래와 같은 결과가 나온다.



  • lib.c를 컴파일 하면 아래와 같은 결과가 나온다.



  • extern 변수가 없으므로 Relocation Table은 존재하지 않는다.





  • 링커가 링킹을 하게되면 각 작은 섹션들의 위치를 정해준다.
  • 이렇게 각 심볼들의 주소들을 계산할 수 있게 된다.



  • 마지막으로 흩어져있는 오브젝트 파일들을 읽어서 동일한 섹션들을 묶어서 하나의 exe 파일로 만든다.

정리

  • Code Segment 와 Data Segment 는 무엇일까?
  • 위에서 설명한것처럼 링킹을 통해 exe 파일을 만들면 각 섹션들이 존재한다(Code Section, data section) 이 섹션들이 같은 이름의 세그먼트 영역에 로드되어 프로그램이 실행된다.
  • 즉 Code section -> Code Segment , Data section -> Data segment
  • BSS Section 은 Data Segment에 합병이 된다.
  • Stack Segment, Heap Segment는 로더가 프로그램을 로딩 하는 시점에 빈 스택과 힙을 만들어준다.
  • Code Segment 와 Data Segment 는 프로그램이 로딩될때 한번 할당된다. 그리고 프로그램이 종료될때 반환된다. -> Static Storage Allocation
  • Stack Segment, Heap Segment 은 다이나믹하게 할당 받는다 -> Dynamic Storage Allocation

출처 - http://yimoyimo.tk/Linker-and-Loader/

:

[수학] -1*-1=1인 이유는

etc 2017. 1. 19. 15:18


음수와 음수를 곱하면 양수가 된다는데, 그냥 그렇다고 외우기만 했을 뿐, 그 이유를 생각해 보지 못했다. 음수끼리 더하면 여전히 음수인데 왜 곱하면 양수가 될까? 생각해 보면, 곱이 양수가 되는 것은커녕 음수끼리 어떻게 곱할 수 있는지도 이해하기 어렵다. 음수와 음수의 곱은 도대체 무엇일까?

스탕달도 파스칼도 음수를 몰랐다

음수를 이해할 수 있는 쉬운 방법 가운데 하나는 아마도 금전적 이익을 양, 금전적 손실을 음으로 생각하는 방식일 것이다. 그런데 이 방식은 음수의 덧뺄셈을 설명하는 데는 좋지만, 곱셈이나 나눗셈을 다루는 데는 오히려 방해가 된다. 일례로, 소설 <적과 흑>으로 유명한 프랑스의 작가 스탕달(Stendhal, 1783-1842)은 자전적 소설에서, “1만 프랑의 빚과 5백 프랑의 빚을 곱하면 어떻게 5백만 프랑의 이익이 된다는 말인가?”라고 썼다. 음수와 음수의 곱이 양수인 것을 이해할 수 없다는 것이다. 당대의 지식인 가운데 한 명인 스탕달이 이 정도였으니, 음수에 음수를 곱해서 양수가 된다는 사실을 선뜻 받아들이지 못하는 사람들이 많았음을 짐작할 수 있다. 사실 무리수보다 음수가 더 늦게 발견됐으며, 음수의 연산을 보편적으로 받아들인 것이 무리수를 받아들인 것보다 나중인 것을 보면, 음수에 대한 거부감 내지는 공포감이 얼마나 심했는지 알 만하다. 희대의 천재로 손꼽히는 파스칼(Blaise Pascal, 1623-1662)조차 “놀랍게도, 아무것도 없는 상태에서 4개를 없애도 여전히 아무것도 없다는 사실을 이해하지 못하는 사람들이 있다”라고 자신의 책에 써놓을 정도였다.


양수와 음수의 모델 : 빚과 이익
‘인간은 생각하는 갈대’라고 말한, ‘파스칼의 원리’를 발견한, 세계에서 처음으로 계산기를 만든 그 파스칼이 말이다. 음수 곱하기 음수가 양수라는 것은 문헌 상으로는 7세기 인도의 수학자 브라흐마굽타(Brahmagupta, 598–668)가 처음 밝혔다. 그렇지만, -3이 2보다 작은데 어떻게 -3의 제곱이 2의 제곱보다 크냐는 반론이 1000년도 더 지난 18세기 유럽에서 버젓이 상식처럼 통용되기도 하였으니, 음수에 음수를 곱한 것이 양수라는 사실에 대한 저항이 만만치 않았음을 알 수 있다. 오늘날처럼 경제나 날씨 등에서 음수의 개념이 일상화된 사회에서는 이러한 저항이 훨씬 덜한 편이지만, 여전히 음수를 처음 배우는 사람들이나 배운지 오랜 사람들에게는 낯설게 느껴지는 것도 사실이다.

스탕달의 예에서처럼 음수와 양수는 “빚”과 “이익”이라는 모델이 있다. 양수를 이익으로 생각하고 음수를 빚으로 생각하면, 이 모델은 양수의 덧셈과 뺄셈을 모두 설명할 수 있기 때문에 매우 좋은 모델이라 할 수 있다. 예를 들어 양수를 더하는 것은 이익이 늘어나는 것이고, 음수를 더하는 것은 이익이 줄어드는 것으로 생각하는 것이다. (이익이 0보다 작으면 빚으로 해석한다.) 인간은 한번 성공한 방법을 상황이 달라지더라도 적용하려는 경향이 있어서, 양수와 음수에 대한 연산을 할 때면 으레 빚과 이익을 생각하기 마련이다. 따라서 음수를 곱해서 양수라는 것을 빚과 빚을 곱해서 이익이라는 모델로 이해하려 시도하는 것도 자연스러운 현상이다. 왜 이 모델이 곱셈을 다룰 때는 잘 작동하지 않는 것일까?

빚에 빚을 곱하지 말라

빚과 이익 모델을 써서 곱하기를 하려고 하면, 양수 곱하기 양수를 설명할 때부터 벌써 삐걱거리기 시작한다. 이 모델대로라면 ‘이익’에 ‘이익’을 곱하면 ‘이익’이라는 말인데 과연 그럴까? 100원짜리가 10개 있으면 1,000원(100 × 10 = 1,000)이므로 양수를 곱하면 양수라는 것은 얼핏 보면 그럴듯한 설명처럼 보인다. 그런데 잘 들여다보면 앞의 100의 단위는 ‘원’이지만, 뒤의 10은 단위가 ‘개수’임을 알 수 있다. 앞의 100원은 ‘이익’이라 불러도 괜찮지만, 뒤의 10개는 ‘이익’이라고 해석하기 곤란한 것이다. 따라서 빚에 빚을 곱하는 것은 고사하고, 이익에 이익을 곱한다는 것부터가 어불성설임을 알 수 있다.

빚과 이익모델 버릴까? 살릴까?

‘이익의 곱은 이익’이라는 말은 틀린 ‘해석’이지만, 빚과 이익 모델로도 일단 양수 곱하기 양수가 양수라는 것을 설명하는 데는 별 문제가 없다. 한편, 이 모델로 음수 곱하기 양수가 음수라는 것도 설명할 수 있다. 예를 들어, 천 원을 빚진 사람이 열 명이면, 전체 빚이 만원임을 안다. 식으로 쓰면 아래와 같이 나타낼 수 있다.



이와 같이 음수 곱하기 양수와 양수 곱하기 음수가 음수라는 것을 설명할 수 있기 때문에 (역시 ‘빚 곱하기 이익이 빚’이라는 얘기는 아니다) 곱셈일 때도 완전히 폐기처분하기에 아까운 모델이기는 하다. 그렇지만 이 모델은 ‘음수 곱하기 음수’를 잘 설명할 수 없다는 것이 결정적 약점이다. 무엇보다 사람수나 개수에는 음수가 없기 때문이다. 물론 이해해 볼 방법이 없는 것은 아닌데, 조금 뒤로 미루자.

음수에 음수를 곱하면 양수이다 : 1.규칙성



위의 곱셈표를 보자. 가로줄을 보면, 곱해지는 수를 하나씩 줄임에 따라 곱셈의 결과도 일정하게 변한다. 세로줄을 보면 곱하는 수를 하나씩 줄임에 따라 역시 일정하게, 첫 번째 세로줄은 2씩 줄고, 두 번째 줄은 1씩 줄고, 세 번째 줄은 0으로 변함이 없고, 네 번째 줄은 1씩 늘고, 다섯 번째 줄은 2씩 늘고 있다. 따라서 다음 가로줄을 만들면 아래와 같이 되어야 원래의 규칙이 유지된다.



이로부터 음수에 음수를 곱하면 양수가 되는 것이 매우 자연스럽다는 것을 알 수 있다. (원한다면두어 줄 더 계산해도 좋다.)

음수에 음수를 곱하면 양수이다 : 2.수직선

음수를 다루는 기본적인 방식 가운데 하나는 수에 방향성을 부여하는 것이다. 양수와 음수를 양의 방향과 음의 방향의 두 가지로 생각하면 모델링 하기에 편리하다. 우리가 잘 알고 있는 수직선()이 바로 그것이다. 수직선에서 3과 -3은 기준점이 되는 원점에서 같은 거리(양)만큼 떨어져 있지만 방향이 서로 반대여서 다른 수가 된다. 사실 수직선 모델이 나온 이후에야 비로소 파스칼처럼 음수의 존재 자체를 부정하는 경향이 사라졌다. 이 수직선 모델에서 2에 3을 곱하는 것은 2를 3번 더하는 것이므로, 수직선의 0에서 양의 방향으로 2칸씩 3번 이동한 결과로 생각할 수 있다.



같은 방식으로 2에 -3을 곱하는 것은 반대 방향으로 2칸씩 3번, 즉 -2만큼 움직이는 과정을 3번 반복한 것으로 생각할 수 있다. 즉, -2에 3을 곱하는 것과 마찬가지로 생각할 수 있다.



이제(-2)×(-3)을 생각해 보면 -2의 반대 방향으로 3번 움직이는 것에 해당하고, 이것은 2를 3번 더한 것과 같아지므로,(-2)×(-3) = 6이 된다.

음수에 음수를 곱하면 양수이다 : 3.빚과 이익 모델

빚과 이익 모델로도 음수의 곱을 설명할 수 있다. 양수만 더하고 빼던 것을, 음수도 더하고 빼는 것으로 확장하는 것이다. 음수를 더하는 것은 빚이 늘어난다, 이익이 줄어든다는 뜻으로 해석하고, 음수를 뺀다는 것은 빚이 줄어든다, 즉, 이익이 늘어난다는 뜻으로 해석하는 것이 합리적이다. 특히 a가 양수일 때,-a를 뺀다는 것은 a만큼의 빚(즉, -a)이 줄었다는 뜻이므로, a만큼의 이익이 늘어났다는 뜻이다. 즉,-(-a) = a인 것이다. 또한 빚과 이익 모델에서 a와 b가 양수일 때(-a) × b = -(a × b) = a × (-b)라는 것은 수긍할 수 있을 것이다. 음수의 곱셈이 기존의 셈법과 어울리려면 저 식이b가 음수일 때도 (혹은 0일 때도) 성립하는 것이 바람직할 것이다. 따라서 b가 음수일 때b = -c로 나타내면, c는 양수이고 (-a) × (-c) = a ×(-(-c)) = a × c여야만 한다.즉, 음수 곱하기 음수는 양수가 되는 것이 합리적이다.

음수에 음수를 곱하면 양수이다 : 4.수학적 증명

음수와 음수의 곱이 양수임을 여러가지로 ‘설명’했지만, 엄밀한 증명이라고 하기는 어렵다. 예를 들어 -와 -의 곱이 임을 위의 설명을 써서 보이기 힘든데, 번, 혹은 개 같은 것을 생각할 수 없기 때문이다. 엄밀한 증명을 위해서는 0이 덧셈의 항등원이라는 것과, 덧셈의 결합법칙, 덧셈과 곱셈 사이의 분배법칙을 이용해여 (-a) × (-b) = ab를 증명할 수 있다. 먼저 음수와 음수의 곱 가운데 가장 간단한 (-1) × (-1) = 1을 연습 삼아 풀어보자. 0 = 1 + (-1)임은 알고 있다. 양변에 -1을 곱하고 분배법칙을 적용하면, 아래와 같다.



1 × (-1) = -1이므로 위의 식은 0=-1+(-1)×(-1) 이 된다. 이제 양변에 1을 더하면 결과가 나온다.



그럼, 이제 일반적인 음수와 음수의 곱에 대해서도 증명해 보겠다. 먼저 0 × b = 0 이라는 것을 증명한다. 0이 만약 3개 있다면 0 × 3 = 0 + 0 + 0 = 0 이니까 이런 것은 쉽다. 하지만 0에다 를 곱한 것도 이렇게 생각할 수 있을까? 0이 번 있다는 것은 상상할 수 없다. 그래서 증명을 하는 것이다. 0 × b = 0의 증명은 다음과 같다.



a ×0 = 0인 것도 마찬가지로 똑같이 보일 수 있다. 이제 본격적으로(-a) × (-b) = ab를 증명하겠다. 그 증명은 아래와 같다.



이제 원하는 사실, (-a) × (-b) = ab의 증명이 끝났다.


관련링크 : [오늘의 과학] "-1 x -1 = 1 ?" 수학자 박부성님이 지식iN에 묻습니다.

관련링크 : 오늘의 과학 저자와의 질의응답 전체보기

박부성 | 경남대학교 수학교육과 교수

출처 - http://navercast.naver.com/contents.nhn?rid=22&contents_id=106

'etc' 카테고리의 다른 글

programmer  (0) 2019.03.28
[수학] 1/0은 왜 안되나  (1) 2017.01.19
부동 소수점 설명  (0) 2017.01.18
부동 소수점의 이해  (0) 2017.01.18
particular, specific, certain  (0) 2016.09.09
:

[수학] 1/0은 왜 안되나

etc 2017. 1. 19. 15:08


많은 사람들이 나눗셈을 할 때 0으로 나눌 수 없다는 말을 들었을 것이다. 0으로 나눌 수 없는 이유는 모든 선생님이 가르쳐 주었을 텐데, 여전히 0으로 나누는 것이 왜 안 된다는 건지 모르겠다는 말을 많이 한다. 다른 수학 문제에 비하면 0으로 나누는 것을 도무지 모르겠다는 사람의 수는 그래도 적은 편이지만, 그래도 끊임없이 제기되는 문제인 것만은 분명하다. 한번 0으로 나눌 수 없는 이유를 짚어보자.


0으로 나누기,한번 해보자




두 실수가 주어지면 나눗셈을 하는 방법은 초등학교 고학년이 되면 배우게 된다. 예를 들어 3.764를 1.9로 나누려고 하면, 아래 그림처럼 나눠가기 시작한다.




이런 나눗셈 방법을 ‘긴 나눗셈’ 한자로는 장제법(長除法) 영어로는 long division이라고 부른다. 이제 같은 방법을 써서 1을 0으로 나눠보자.




좀처럼 나눗셈이 되지 않는 것을 알 수 있다. 물음표 부분에 어떤 수를 쓰더라도 파란색으로 쓴 부분이 0이 되어 도무지 소거가 안 되는 것이다. 이 경우에는 ‘아무리 나누고 싶어도 몫을 구할 수 없으므로’ 나눗셈이 불가능한 것이다. 어떤 수든 0이 아닌 수를 0으로 나누면 같은 현상이 생긴다. 이번에는 긴 나눗셈을 써서 0을 0으로 나눠보자.




이번에는 조금 전과 상황이 다른데, 물음표 부분에는 1을 쓰든, 2를 쓰든 어떤 수를 쓰더라도 나눗셈이 단번에 끝난다. 하지만 이래서야 몫이 1인지, 2인지 알 도리가 없다. 따라서 0으로 나눈 값을 결정할 수가 없다! 이 경우엔 ‘몫을 정할 수 없어서’ 나눗셈이 안 되는 것이다.



컴퓨터도 0으로 나누라고 하면,못 하겠다고 버틴다






계산기에 1을 0으로 나눠본 결과



이처럼 0으로 나누려고 하면 긴 나눗셈은 통하지 않는다. 그렇지만, 혹시 뭔가 신비하고 특별한 다른 나눗셈을 쓰면 0으로 나눌 수 있지 않을까? 수학자들에게는 숨겨놓은 비장의 방법이 있지 않을까? 수학의 원리가 가장 잘 들어있는 컴퓨터에게 0으로 나누기를 시켜 보면 어떨까?


예를 들어 윈도 계열 운영체제에서는 컴퓨터 프로그램 수행 중에 긴급 상황이 발생하면, 중앙처리장치로 ‘인터럽트’라는 것을 보내 프로그램을 잠시 멈추고 컴퓨터의 처리를 기다린다. 그런데, 이런 인터럽트가 발생하는 상황 중 가장 상위에 있는 것이 바로 ‘0으로 나누기’이다. 프로그램이 0으로 나눌 것을 요청하면 중앙처리장치에서는 ‘0으로 나누는 것은 오류’, ‘0으로 나눌 수 없습니다’ 영어로는 ‘Divide by 0’라는 결과를 내보낸다. 이 오류를 잘못 처리하면 심할 경우 파란 화면을 띄우고 나 몰라라 하는 경우도 있다. 예를 들어 윈도 계산기로 1÷0을 시키면 이런 화면을 볼 수 있다.


그런데 컴퓨터는 왜 0으로 나눌 수 없다고 하는 것일까? 먼저 근본적으로 컴퓨터는 나눗셈을 못한다는 것부터 언급해야겠다. 계산 능력이 탁월한 컴퓨터가 나눗셈을 못하다니 무슨 뚱딴지 같은 소리냐고 오해는 하지 말길 바란다. 컴퓨터가 나눗셈을 못한다는 말은, 컴퓨터가 나눗셈을 할 때 ‘뺄셈’을 반복해서 처리한다는 뜻으로 한 말이다. 사실은 뺄셈도, 덧셈과 보수 연산을 이용해서 처리한다. 어쨌든 0으로 나누려면 0을 빼는 일을 반복해야 하는데, 0을 아무리 빼도 값이 변하지 않으므로, 뺄셈만 반복하며 무한 루프에 빠져 버릴 것이다. 그냥 뒀다가는 0만 빼다가 세월 다 보낼 테니, 0으로 나누는 것을 금지할 수밖에 없는 것이다.

나눗셈의 정의를 바꾸지 않는 한,누구도 0으로는 못 나눈다




사실 이미 감은 잡혔겠지만, 누가 뭐래도 0으로 나누는 것은 불가능하다는 것을 ‘증명’할 수 있다. 이를 위해서는 나눗셈이 ‘곱셈의 역연산’임을 돌이켜 생각해 보기만 하면 된다. a÷b를 계산하여 c가 나온다는 것은 c×b = a가 성립한다는 뜻이다. 예를 들어, 3÷2가 1.5인 것은 1.5×2 = 3이 성립하기 때문이다. 이제 예를 들어 3을 0으로 나눌 수 있다고, 즉, 3÷0 = c 를 만족하는 c를 구할 수 있다고 해 보자. 정의에 따라 c×0 = 3이 성립한다는 말과 마찬가지다. 그런데, ‘음수 곱하기 음수는 양수’를 설명할 때 증명한 적도 있지만, 왼쪽 변은 항상 0이다! 따라서 0=3이 성립하게 되어, 모순이 발생한다. 모순이 생겼다는 것은 중간 단계 어디선가 잘못했다는 뜻인데, 어디가 잘못인지 알기 위해서는 거꾸로 올라가는 것이 도움이 된다. 즉, 0이 3과 다르다는 것에서 거꾸로 올라가면, 애초 c×0 = 3 이 성립하는 c가 있다고 가정했던 것이 잘못이라는 뜻, 즉, 3÷0=c인 c를 구할 수 없다는 뜻이 된다! 따라서 0으로 나누는 것은 불가능하다.


그런데 이런 설명으로는 0÷0을 구할 수 없다는 얘기를 하기에는 불충분하고, 조금 보충 설명이 필요하다. 이제 0÷0이 계산 가능하다고 하자. 이때는 1×0 = 0 , 2×0 = 0인 것을 알기 때문에 나눗셈의 정의로부터 0÷0 = 1 및 0÷0 = 2가 성립할 것이다. 따라서 1 = 2가 되어야 한다. 이것 역시 모순이다. (왜 모순일까? 예를 들어 페아노 공리계의 용어를 쓰면 1=1’인데, 이는 1이 어떤 수의 다음수도 아니라는 데 모순이다!) 이런 모순은 0÷0이 계산 가능하다는 가정을 한 데서 생기는 모순이다. 따라서 0÷0 역시 불가능하다.


그런데 왜 하필 0으로만 나눌 수 없나?




예를 들어 1.8으로는 나눌 수 있고, -π로도 나눌 수 있는데, 왜 하필 0으로만 안 되는 걸까라는 질문을 해 볼 수 있다. 이미 답은 나온 셈이지만, 0이 뭐 그리 대단한 수라서 그런 특혜를 누리는 걸까? 사실 0은 대단한 수가 아니라고 생각할 수도 있다. 어떤 수든 0을 더해도 그대로이기 때문에, 덧셈에 관한 한 0은 있으나마나 한 변변치 못한 수니까. 그러나 0을 빼놓고 생각하는 덧셈은 ‘오아시스 없는 사막’이라는 것을 알아 주기 바란다. 0이 덧셈에서는 변변치 못했을지는 몰라도, 곱셈에서만큼은 어마어마하게 사정이 다르다. 가히 무소불위의 권력을 휘두른다. 어떤 수를 곱해도 그 수를 무력하게 만들고 결과를 0으로 만들기 때문이다. 그런데 이런 성질을 갖는 수는 0밖에 없다! 바로 이런 이유 때문에 0으로는 나눌 수 없는 것이다. 본질적으로는 같지만, 조금 다른 방식으로 설명해 보자. 예를 들어 4×b를 생각하자. 이 값은 b가 달라지면 결과가 달라진다. 또한, 모든 수가 곱셈 결과가 될 수 있다는 것도 (예를 들어, 긴 나눗셈을 해 보면) 알 수 있다. 이 두 가지 성질은 4를 다른 수로 바꿔도 성립하는데, 오로지 0만 예외다. 0×b를 생각하면, b가 달라도 결과가 달라지기는커녕, 결과는 0 하나밖에 안 나온다! 적어도 곱셈에 대해서는 (따라서 나눗셈에 대해서도) 0만큼은 특별 대접을 하지 않을 수 없는 것이다.


0으로 나누면 무한대라던데요




0을 맨 처음 수로 취급한 인도에서 0으로 나누는 문제를 맨 먼저 고민했을 거라는 사실은 짐작할 수 있는데, 일례로 12세기의 유명한 인도 수학자 바스카라(Bhaskara Acharya, 1114~1185)는 자신의 저서 “릴라바티(Lilavati)”에서 1÷0을 무한대로 취급하였다. 사실 현대 수학자들도 극한의 개념을 써서 이렇게 취급하는 경우가 있을 만큼, 이런 주장에는 장점도 있다. 하지만 섣불리 1÷0을 무한대로 취급하는 것은 자칫 오해를 부를 수 있으므로 조심하는 게 좋다. 첫째, 1÷0 = ∞ 라는 말은, 1 = ∞ x 0 을 뜻하는 말이 아니라는 것이다. ∞는 숫자도 아니므로 무작정 숫자와 곱셈을 할 수는 없는 것이다. 둘째, 1÷0 = ∞ 라면 당연히 -1÷0 = -∞로 취급해야 할 것이다. 그렇다고 예를 들어 다음과 같이 주장하는 ‘우’를 범해서는 안 된다.




무한대는 수가 아니므로, 무한대와 관련한 연산은 보통의 의미에서의 사칙 연산의 규칙을 그대로 따르지 않을 수 있기 때문이다. 사실 무한대와 관련한 연산은 ‘극한의 개념’이나 ‘확장된 실수계의 개념’ 등을 이용할 때 비로소 제대로 된 의미를 가지는데, 그런 개념을 소개하는 것은 이 글이 의도하는 바의 범위를 넘으므로 생략하기로 한다. 그러나, 1÷0 = ∞ 이라는 표기를 쓴다고 해서 여전히 ‘0으로 나눌 수 있다’는 얘기는 아님을 다시 한 번 강조해 두고 싶다.


관련글 : -1×-1=1인 이유는?



글 정경훈 / 서울대 기초교육원 강의교수




출처: http://sonseungha.tistory.com/33 [Linuxias]

'etc' 카테고리의 다른 글

programmer  (0) 2019.03.28
[수학] -1*-1=1인 이유는  (0) 2017.01.19
부동 소수점 설명  (0) 2017.01.18
부동 소수점의 이해  (0) 2017.01.18
particular, specific, certain  (0) 2016.09.09
: