여기서 n의 보수(compliment)라는 용어의 뜻은 주어진 수치의 각 자리의 값을 n-1에서 감산하고 그 결과의 최하위의 자리에 1을 가산하여 구하는 수치를 뜻합니다. 예를 들어 10100 이라는 2진수 숫자가 있는 경우 1의 보수는 01011입니다. 2의 보수를 구하는 방법은 1의 보수의 결과에 1을 더하면 됩니다.

2의 보수 계산시 주의할 점은 캐리(한 자리 올리는 수)을 고려해야 하는 것입니다. 위의 그림을 보면 1의 보수에서 1을 더하는 계산을 할 경우 각 자리가 캐리와 같다면 결과는 0이 되며 캐리는 1이 됩니다. 각 자리가 캐리와 다르다면 결과는 1이 되며 캐리는 0이 됩니다(빨간색 부분) . 첫 번째 자리(맨 오른쪽)가 0이라면 그냥 더하면 되지만 만약 1이라면 여기서 숫자 1을 더한 경우 자리올림 처리를 해야 합니다.

import java.util.Scanner;

public class TwosComplement {

  public static void main(String[] args) {

    try(Scanner s = new Scanner(System.in);){
      System.out.print("2진수 다섯 자리의 숫자를 입력하시오.>> ");        
      char[] binary = s.nextLine().toCharArray();
      int[] oneComp = new int[5];
      int[] twoComp = new int[5];        

      int i = 0;
      int n = binary.length;

      do {
        // 각 자릿수가 1이면 0으로 바꾸고, 0이면 1로 바꿈
        oneComp[i] = 1 - (int) (binary[i] - 48);
        // oneComp[i] = binary[i] == '1' ? 0 : 1;
        i++;            
      } while(i < n);    // 0, 1, 2, 3, 4

      seeArray(oneComp, 1);

      i = n - 1;    // 4

      int carry = 1;

      // 역순으로 2의 보수 배열에 집어넣음
      do {
        twoComp[i] = 1;  // 일단 자릿수와 캐리가 다르다고 가정                        
        if (oneComp[i] == carry)    twoComp[i] = 0;            
        carry = oneComp[i] * carry;            
        i--;            
      } while(i >= 0);    // 4, 3, 2, 1, 0

      seeArray(twoComp, 2);    
    }

  }

  public static void seeArray(int[] array, int comp) {
    System.out.print(comp + "의 보수: ");
    for(int i = 0; i < array.length; i++) {
      System.out.print(array[i] + " ");
    }
    System.out.println();
  }

}

여기서 18라인을 보면 1과 0을 서로 바꾸는(toggle) 코드인데요, 먼저 char 타입으로 입력받은 임의의 문자 '0' 또는 '1'을 정수형(int)으로 변환합니다. 그런데 변환하면 0 또는 1이 되는 것이 아니고 해당 문자에 대항하는 아스키 코드인 48 또는 49가 반환되게 됩니다. 이것을 48로 빼서 1이 나오면 1(아스키 49)이고 0이라면 말 그대로 0(아스키 48) 입니다.

18라인을 위와 같이 하지 않고 단순히 문자가 같은지 비교하는 방법도 있습니다.

oneComp[i] = binary[i] == '1' ? 0 : 1;
2진수 다섯 자리의 숫자를 입력하시오.>> 10100 
1의 보수: 0 1 0 1 1 
2의 보수: 0 1 1 0 0

 

위의 예제는 정보처리기사 실기 문제의 예제의 답안을 따라 작성한 것입니다. 굳이 정보처리기사 문제풀이가 필요 없다면 다음과 같이 Integer의 메소드를 사용하여 작성할 수 있습니다.

import java.util.Scanner;

public class TwosComplement2 {

  public static void main(String[] args) {

    try(Scanner s = new Scanner(System.in);){
      
      while(true) {
        System.out.print("2진수 다섯 자리의 숫자를 입력하시오. (종료: Enter) >> "); 

        String binary = s.nextLine();
        if(binary.equals("")) {
          System.exit(0);
        }
        
        int decimal = Integer.parseInt(binary, 2);
        String comp1 = Integer.toBinaryString(~decimal).substring(27, 32);
        String comp2 = Integer.toBinaryString(~decimal + 1).substring(27, 32);
        
        System.out.println("1의 보수: " + comp1.replaceAll(".(?!$)", "$0 "));
        System.out.println("2의 보수: " + comp2.replaceAll(".(?!$)", "$0 "));
        System.out.println();
      }  

    }

  }
  
}
2진수 다섯 자리의 숫자를 입력하시오. (종료: Enter) >> 10011
1의 보수: 0 1 1 0 0
2의 보수: 0 1 1 0 1

2진수 다섯 자리의 숫자를 입력하시오. (종료: Enter) >> 00110
1의 보수: 1 1 0 0 1
2의 보수: 1 1 0 1 0

2진수 다섯 자리의 숫자를 입력하시오. (종료: Enter) >>