. Java의 정석

[Java] 음수의 2진 변환, 2의 보수법, 부호비트

박인영 2021. 7. 3. 11:32

 

앞서 데이터 타입별로

저장 가능한 값의 범위에 대하여 아래와 같이 정리했다.

정수형 byte 타입의 경우,

크기는 1 byte이며 8bit이다.

 

8bit는 8자리의 2진수로,

0000_0000부터 1111_1111까지

2⁸, 즉 256개의 값 표현이 가능하다.

 

byte는 정수이기 때문에 음수가 존재해야 한다.

256개를 음수와 0, 양수로 나눠 써야 하는데,

 

마침 8자리의 2진수 256개 중

절반인 128개는 0으로 시작하고

(0000_0000 ~ 0111_1111)

나머지 절반 128개는 1로 시작한다.

(1000_0000 ~ 1111_1111)

 

0으로 시작하는 절반은 양수로

1로 시작하는 절반은 음수로 표현할 수 있는 것이다.

 

이는 2진수의 제일 왼쪽 1bit가

값의 부호를 결정한다는 의미가 된다.

(그래서 2진수의 제일 왼쪽의 1bit를

MSB(most significant bit)이라고 한다.)

 

0000_0000은 0이고

0000_0001부터 0111_1111까지 127개가 양수이며

1000_0000부터 1111_1111까지 128개가 음수가 된다.

 

부호를 결정하는 제일 왼쪽의 1bit를 제외한

나머지 7bit로 값을 표현해야 한다.

 

양수 중에서는 111_1111이 가장 큰 값, 최대값이 된다.

2진수 111_1111을 10진수로 변환하면 127이 된다.

 

음수 중에서도 111_1111이 가장 큰 값이 되어야 하기 때문에

1111_1111은 음의 정수 중 가장 큰 값인 -1이 된다.

반대로 000_0000이 가장 작은 값이 되어야 하기 때문에

128개의 음수 중 가장 작은 -128이 된다.

이는  2의 보수법에 의한 음수 배치이다.

 

<2의 보수법>

어떤 수의 'n의 보수'는 더했을 때 n이 되는 수를 말한다.

7의 '10의 보수'는 3이고, 3의 '10의 보수'는 7이다.

3과 7을 더하면 자리올림이 발생하고 0이 된다.

이것을 3과 7은 보수의 관계에 있다고 한다.

 

'2의 보수' 관계 역시, 더해서 2가 되는 관계를 말하며

10진수 2는 2진수로 '10'이다.

2진수 '10'은 자리올림이 발생하고 0이 되는 수를 뜻한다.

그래서 '2의 보수 관계'에 있는

2진수 1과 2진수 1을 더하면

자리올림이 발생하고 0이 된다.

 

위 식에서 알 수 있듯이 0101_0101의 2의 보수는 1010_1011이다. 

0101_0101과 1010_1011은 서로 '2의 보수 관계'에 있으며

이 두 2진수를 더하면 0이 된다.

 

2진수 0101_0101은 10진수로 85이며

더해서 0이 되는 2진수 10101011은

10진수로 -85이어야 한다.

 

위 표는 8자리의 2진수와 2의 보수법으로 표현한 10진수 중 일부이다.

0000_0010과 1111_1110 역시 서로 '2의 보수 관계'에 있으며

이 두 2진수를 10진수로 변환하면 부호는 다르지만 절대값이 같다.

이렇게 절대값이 같고 부호가 다른 두 10진수를 표현하는 것을 '2의 보수법'이라고 하며,

현재 대부분의 시스템이 '2의 보수법'으로 부호 있는 정수를 표현한다.

 

 

 

<음수를 2진수로 표현하기>

10진 음의 정수를 2진수로 변환해야 한다면

 

10진 음의 정수를 절대값한 다음

10진 양의 정수를 2진수로 변환하고

이 2진수의 '2의 보수'를 구하면

그 값이 10진 음의 정수를 2진수로 변환한 값이 된다.

 

[ 10진수 -5 ]

   ↓ 절대값

[ 10진수 5 ]

   ↓ 2진수 변환 (8bit)

[ 2진수 0000_0101 ]

   ↓ 2의 보수

[ 2진수 1111_1011 ]

 

∴ 10진수 -5 = 2진수 1011

 

 

 

<2의 보수 구하기 : 2의 보수 = 1의 보수 + 1>

2의 보수를 구할 때 어떤 수를 더하면 0이 되는지를 알아내는 방법도 있고

0000_0101 + ????_???? = (1) 0000_0000

반대로 빼기를 이용해 알아내는 방법도 있다.

(1) 0000_0000 - 0000_0101 = ????_????

((1)은 자리올림으로 발생되었으나 자리수를 넘어가서 버려지는 수이다)

 

그보다 더 간편한 방법이 있다.

바로 1의 보수를 구한 다음 1을 더하면 된다.

 

1의 보수는 0을 1로, 1을 0으로만 바꾸면 되므로 구하기 쉽다.

예를 들어 0101_0101에서

0을 1로, 1을 0으로 바꾸면

1010_1010이 되고 이것이 1의 보수이다.

여기에 1을 더하면 1010_1011이 되고 

이 값은 상단에서 계산했던 2의 보수와 일치한다.