프로그래밍 기초

컴퓨터의 음수 표현과 보수법

hs-archive 2021. 9. 8. 23:49

https://unsplash.com/photos/D0Wd-7LLCpM

컴퓨터는 어떻게 음수를 나타낼까?

 

 

 

 

 


얻어갈 지식

  • 보수법
  • MSB ( most significant bit )

 

 

 

 

 

"보수법"

 

우선 컴퓨터가 음수를 표현하는 방법을 알아보기 전에 보수법에 대해 알아보자.

 

보수란 보충해주는 수라는 의미다.

 

좀 더 자세히 말하면

R진법의 수 X가 있을 때 X를 R의 최소 제곱수가 되도록 만드는 수를 R의 보수라 고한다.

10진법의 수 3이 있을 때 3을 10의 최소 제곱수 ( 이 경우 10 )로 만드는 수는 7이므로 ( 3+7=10 ) 10진법 3의 10의 보수는 7이다.

10진법의 수 12가 있을 때 12를 10의 최소 제곱수( 이 경우 100 )로 만드는 수는 88이므로 ( 12+88=100 ) 10진법 12의 10의 보수는 88이다.

 

일반적으로 R진법에는 R의 보수와 R-1의 보수가 존재한다.

10진법에는 10의 보수와 9의 보수가 존재하고,

2진법에는 2의 보수와 1의 보수가 존재하는 것이다.

 

보수를 구하는 공식은 다음과 같다.

R진법 N자릿수 X의 R의 보수 = R의 N승 - X

R진법 N자릿수 X의 R-1의 보수 = R의 N승 - 1 - X

 

위 공식을 사용하면 10진법 3 자릿수 567의 9의 보수는 10^3 - 1 - 567 = 999 - 567 = 432가 된다.

( 10의 보수는 9의 보수에서 1을 더하면 되므로 이 경우 10의 보수는 433이 된다. )

 

이때 식 999-567 = 432를 999 = 567+432로 바꿀 수 있다.

10진수 567의 9의 보수는 567을 999로 만드는 숫자인 것이다.

다시 말해, R진수 X의 R-1의 보수는 X의 각 자리에 들어가는 숫자를 R-1로 만드는 숫자인 것이다.

8진수 123의 7의 보수를 구하는 식은 123의 각 자리에 들어가는 숫자를 모두 777로 만드는 숫자이므로 654이고,

7진수 543의 6의 보수를 구하는 식은 543의 각 자리에 들어가는 숫자를 모두 666으로 만드는 숫자이므로 123이다.

 

이것을 2진수에 적용하면

2진수 101의 1의 보수를 구하는 식은 101의 각 자리에 들어가는 숫자를 모두 111로 만드는 숫자이므로 010이고,

2진수 1001의 1의 보수를 구하는 식은 1001의 각 자리에 들어가는 숫자를 모두 1111로 만드는 숫자이므로 0110이다.

따라서 2진수 X의 1의 보수는 X의 모든 비트를 반전한 것과 마찬가지다.

 

 

 

 

 

"음수 표현"

 

signed 키워드를 사용하면 변수는 음수 값을 가질 수 있다. (signed, unsigned 참조)

 

컴퓨터는 음수를 bit를 활용하여 표현하는데.

 

컴퓨터가 bit를 사용하여 음수를 나타내는 방법은 부호 크기 방식, 1의 보수법을 활용한 방식, 2의 보수법을 활용한 방식 총 3가지가 있다. 각각의 방식에 대해 알아보자.

 

부호 크기 방식 ( signed-magnitude )

MSB( 제일 왼쪽 비트 )를 식별자로 사용하여 해당 값이 음수인지 양수인지 나타내는 방법이다.

MSB가 0이면 양수고 1이면 음수다.

 

8bit로 예를 들면 다음과 같다.

0000 0001 = 1

1000 0001 = -1 ( MSB를 1로 바꿈 )

 

이렇게 하면 MSB만 보고 해당 수가 음수인지 양수인지 직관적으로 판단할 수 있다.

다만 몇몇 단점이 존재한다.

 

우선 첫 번째로 +0과 -0이 존재한다. ( 0000 0000은 +0이고 1000 0000은 -0이다 )

 

만약 아래와 같은 코드가 있다고 할 때 0이 두 개인 경우는 한 개인 경우보다 복잡한 계산을 해야 할 것이다.

 

if(k >= 0) {
  // ......
}

 

 

둘째로 계산을 할 때 과정이 복잡해진다.

 

-12+4를 하면 -8이 나와야 한다. 하지만 이것을 단순히 계산하면

 

  1000 1100 = -12

+0000 0100 = + 4

=============

  1001 0000 = -16

 

-8이 나오는 것이 아니라 -16이 나온다.

 

signed-magnitude 방식에서는 -12+4 같은 경우 단순히 더해선 안 되고 -로 묶은 뒤 빼기 연산을 하고 MSB의 값을 1로 바꿔야 한다.

 

  0000 1100 = 12

- 0000 0100 =  4

=============

  0000 1000 =  8

 

위의 결과인 0000 1000의 MSB를 1로 변환하면 최종 결괏값인 -8이 나온다.

1000 1000 = -8

 

위처럼 MSB를 양수, 음수의 식별자로 사용하는 방법은 어느 때는 그대로 덧셈을 하고 어느 때는 반대로 뺄셈을 한 뒤 MSB값을 바꾸는 등 회로 구성할 때 생각해야 할 것들이 많다. ( 게다가, 덧셈 계산과 뺄셈 계산은 서로 다른 작업이므로 각각 구현해야 하는데 자연스럽게 구성이 복잡해진다. )

 

장점

- 사람이 볼 때 MSB만 보고 양수, 음수를 파악할 수 있어 직관적이다.

 

단점

- 0을 표현하는 방법이 2가지가 있다.

- 셈을 할 때 고려해야 할 것이 많아지고 회로가 복잡해진다.

 

1의 보수를 활용

1의 보수든 2의 보수든 보수법을 활용하면 음수를 양수로 나타낼 수 있다.

 

우선 1의 보수를 활용하여 음수를 표현하는 방법이다.

10진수 1을 8비트 2진수로 나타낸 0000 0001의 1의 보수 1111 1110은 -1을 나타낸다.

10진수 3을 8비트 2진수로 나타낸 0000 0011의 1의 보수 1111 1100은 -3을 나타낸다.

 

 

1의 보수를 활용하여 -23 + 31을 계산해보자

우선 -23은 23의 1의 보수이므로

0001 0111의 1의 보수 1110 1000이 -23이다 따라서

 

   1110 1000 = -23

+ 0001 1111 = +31

=============

 1 0000 0111

 

10진수 0을 8비트 2진수로 나타낸 0000 0000의 1의 보수는 1111 1111 이므로 1111 1111은 0이다.

0+1=1 이므로 1111 1111 + 0000 0001 = 1 0000 0000 = 0000 0001이다 따라서,

1 0000 0111

= 0000 0111 + 0000 0001

= 0000 1000

= 8 

 

-23+31의 결과 값인 8이 나오게 된다.

 

이번에는 -12+4를 계산해보자

우선 -12는 12의 1의 보수이므로

0000 1100의 보수 1111 0011이 -12이다 따라서

 

   1111 0011

+ 0000 0100

=========

   1111 0111

 

MSB에서 올림이 발생하지 않았으므로 +1을 하지 않아도 된다.

1111 0111은 10진수로 247이고 signed 8비트는 247을 나타낼 수 없으므로 이는 어떤 수의 1의 보수라고 봐야 한다.

1111 0111의 1의 보수는 0000 1000이고 해당 값은 10진수로 8이므로

1111 0111은 247이 아니라 -8을 나타내는 것이다.

 

-12+4의 결과 값인 -8이 나온 것이다.

 

 

1의 보수를 사용하면 음수를 양수로 대체할 수 있으니 뺄셈을 모두 덧셈으로 대체할 수 있게 되고 결국 뺄셈은 구현하지 않아도 되니 부호 크기 방식보다 설계가 편해지지만 아직까지 문제점이 존재한다.

첫째로 여전히 +0과 -0이 존재한다는 것이고 ( 0000 0000도 0이고 그것의 1의 보수인 1111 1111도 0이다. )

둘째로 위에서 본 것처럼 캐리의 여부를 판단한 뒤 이어서 추가 계산을 해야 한다는 것이다.

 

장점

- 비트만 반전시키면 음수 값을 얻을 수 있다.

- 음수를 양수로 표현하므로 뺄셈을 덧셈으로 구현할 수 있어 회로가 단순해진다.

 

단점

- 캐리가 발생하는 경우를 처리해줘야 한다.

- 0을 표현하는 방법이 두 가지이다.

 

2의 보수를 활용

2의 보수를 활용하면 0은 오직 0000 0000으로만 나타낼 수 있게 된다.

 

   0000 0000의 2의 보수는

1 0000 0000이므로 8비트로 할 수 있는 0의 표현은 오직 1개가 된다.

그리고 2의 보수를 활용할 때는 MSB에서 올림이 발생할 경우 해당 값을 그냥 무시한다 ( 1 0000 0000 = 0이니까 )

 

2의 보수를 활용하여 -23 + 31을 계산해보자

-23은 23의 2의 보수이므로

0001 0111의 2의 보수 1110 1001이 -23이다 따라서

 

   1110 1001 = -23

+ 0001 1111 = +31

=============

1 0000 1000

 

1 0000 1000

= 0000 1000

= 8

 

-23+31의 결과 값인 8이 나오게 된다. 

 

이번에는 -12+4를 계산해보자

우선 -12는 12의 2의 보수이므로

0000 1100의 보수 1111 0100이 -12이다 따라서

 

   1111 0100

+ 0000 0100

=========

   1111 1000

 

1111 1000은 10진수로 248이고 signed 8비트는 248을 나타낼 수 없으므로 이는 어떤 수의 2의 보수라고 봐야 한다.

1111 1000의 2의 보수는 0000 1000이고 해당 값은 10진수로 8이므로

1111 1000은 -8을 나타낸 것이다.

 

-12+4의 결과 값인 -8이 나온 것이다.

 

2의 보수의 장점은 아래와 같다.

 

장점

- 1의 보수에 1을 더하면 음수 값을 얻을 수 있다.

- 덧셈만으로 뺄셈을 구현할 수 있어 회로가 단순해진다.

- 1의 보수의 단점이 모두 해결된다. ( 0이 2개인 문제, 캐리 값에 따라 셈을 추가로 해줘야 하는 문제 )

 

 

 

 

 


https://o.playgm.co.kr/427

 

보수의 개념과 2의 보수

○ 개념 보수는 뺄셈을 덧셈으로 계산할 때 사용합니다. 예를 들어보자면, 80 - 48이라는 식이 있다고 했을 때, 48의 10의 보수는 52. 80 + 52 = 132이고요, 여기서 삐져나온 자릿수 100을 빼면 32가 됩

o.playgm.co.kr

https://st-lab.tistory.com/189

 

2진수의 수와 음수 표현법 [1의 보수와 2의 보수]

안녕하세요. 오늘은 프로그래밍이 아닌 컴퓨터의 연산에 대해 이해해보고자 합니다. 우리가 흔히 프로그래밍을 할 때는 그나마 사람에 가까운 언어로 된 고급언어들로 작성을 하지만 실제 컴퓨

st-lab.tistory.com

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

 

1의 보수와 2의 보수에 사용에 대해...

보수는 무엇이고 그 보수가 컴퓨터 시스템에 적용될때 필요한 것은 어떤 것인가. 생각해보자. 하나하나씩. ...

blog.naver.com

 

'프로그래밍 기초' 카테고리의 다른 글

동적 배열  (0) 2022.05.29
32bit vs 64bit  (0) 2021.10.06
Java에서 String 생성 시 ""와 new 의 차이  (0) 2021.09.09
비트 패턴  (0) 2021.09.09
signed, unsigned  (0) 2021.09.08