brunch

You can make anything
by writing

C.S.Lewis

by zwoo Oct 26. 2021

[DATA TIL] 0과 1의 체계에서 음수 표현하기

한정된 메모리, 오버플로우, 부호비트, 1의 보수, 2의 보수

보수라는 개념을 공부했다. 보수는 보충해주는 수를 의미한다. 1과 9를 더해서 10이 되므로, 1과 9는 결과값 10에 대해 서로의 보수이다. 



0과 1의 체계에서 음수 표현하기 


마이너스 부호를 원래부터 가지고 태어난 숫자는 없다. '-' 이 기호는 음수 공간을 표현하기 위해 사람들이 숫자 앞에 임의로 붙인 부호이다. 따라서 0과 1을 가지고 연산하는 컴퓨터가 특정 숫자를 음수라고 판단할 수 있으려면, 각 숫자에 할당해주는 비트 중에서 한 자리는 부호를 명시하는 자리로 지정해줄 필요가 있었다. 물론 '-' 라는 기호를 사용할 수는 없기 때문에 부호비트 자리에 0이 있으면 그 수는 양수, 1이 있으면 음수를 가리키는 것으로 정해졌다. ( 양수만 사용하는 경우에는 부호가 필요없으므로 unsinged int 라는 자료형을 사용하여 부호비트 자리까지 사용하여 저장가능한 양수의 범위를 두배로 늘릴 수 있다 )


여기에서 흥미로운 질문이 한가지 생긴다.


부호가 필요없는 0에는 부호비트를 안 붙여도 될까?


그렇지 않다. 비트 공간 한자리를 부호비트로 내준다는 게 내키지 않을 수는 있지만, 0이라는 숫자만 특별히 부호비트 없이 표현하는 것은 불가능하다. 숫자는 숫자 자신으로 있을 때보다 다른 숫자들과 연산되는 관계에 놓이는 경우가 훨씬 더 많다. 0을 더하거나 빼거나 어떤 연산의 결과로 0이 나오는 경우들을 생각할 때, 0도 다른 정수들과 자릿수를 일치시키는 것이 자연스럽다.  



뺄셈해보기

1010(2) - 1010(2) = ?

십진수 10에서 십진수 10을 빼면 결과는 0이 된다. 컴퓨터도 마이너스 부호를 만났을 때 뺄셈로직을 수행할 법도 하지만, 뺄셈로직은 존재하지 않는다. 그래서 사람들은 이진수로도 뺄셈이 가능하도록 할만한 다른 방법을 고안해냈다. 그것은 바로 정수형 자료형에게 부여된 한정된 메모리를 이용하여, 7비트의 자릿수보다 한자리 더 넘치게 만들고, 빼는 수의 1의 보수 혹은 2의 보수를 구해서 연산하는 방법이다. 



1의 보수

특정 수의 1의 보수는 각 자릿수를 0은 1로, 1은 0으로 서로 뒤바꾸면 된다. 비트 연산자 NOT(~) 을 사용한 연산이라고 볼 수 있다. 


2 - 1 = 1 

0010(2) - 0001(2) 
= 0010(2) + 1110(2)
   -> 결과값에서 자리올림이 생기므로 최하위 비트 +1 = 0001
   (결과값에서 자리올림이 생기지 않으면 결과값의 1의보수를 다시 구한 후 - 부호 붙이기)


1의 보수를 구해서 덧셈을 하는 경우, 자리올림이 생기는 경우 최상위비트로 올라간 1은 사라지고, 1은 다시 돌아서 최하위 비트에 더해진다. 위의 예시에서 덧셈결과가 10000이 되므로 최상위비트 1은 사라져서 0000이 되고, 최하위비트에 1을 더해 0001을 최종 결과값으로 구할 수 있다. 


반면, 덧셈에서 자리올림이 생기지 않는 경우에는 결과값을 다시 1을 기준으로 반대쪽에 있는 보수를 구한 후, 부호비트를 반대로 바꾸어준다. 



2의 보수

결과값에서 1을 더하는 게 번거롭다면 빼는 수의 2의 보수를 구해서 연산을 할 수도 있다. 


2 - 1 = 1 

0010(2) - 0001(2) 
= 0010(2) + 1111(2)
   -> 결과값에서 자리올림이 생기므로 자리올림 제외한 나머지 부분이 결과값 = 0001
   (결과값에서 자리올림이 생기지 않으면 결과값의 2의보수를 다시 구한 후 - 부호 붙이기)


이 예시처럼 2의 보수를 구해서 더하는 경우, 자리올림을 포함하여 10001 이 결과값이므로 자리올림부분을 제외한 0001이 최종 결과값이 된다. 


그러므로 십진수 10에서 10을 빼는 연산을 이진수로 하면 다음과 같다. 

1010(2) - 1010(2) 
-> 1010(2) + 0101(2) = 1111(2)
-> 1111(2) 의 1의 보수는 0000 
( 최상위비트를 고려하면 10000000(2) = -0 )





TMI 1.

왜 뺄셈로직을 안 만들어둔 것인지 생각을 해봤는데, 보수 연산에 비해 너무 복잡했던 게 아닐까?

마이너스 부호가 별도의 연산자로 존재하는 게 아니고 음수표기를 위해 숫자에만 붙이는 것이므로 이 부호가 뺄셈을 의도하는 것인지 음수 표기를 의도하는 것인지 불명확한 경우들이 예상되는 것 같다. 







Photo by Chris Liverani on Unsplash


http://tcpschool.com/c/c_refer_negativeNumber


https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kmc7468&logNo=220842771599


https://ko.wikipedia.org/wiki/Signed%EC%99%80_unsigned


https://ko.wikipedia.org/wiki/1%EC%9D%98_%EB%B3%B4%EC%88%98


https://ndb796.tistory.com/4


https://www.informit.com/articles/article.aspx?p=31670&seqNum=2



매거진의 이전글 [JS TIL] 논리연산자 && 를 조건문처럼 쓰지말자
작품 선택
키워드 선택 0 / 3 0
댓글여부
afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari