2026년 02월 08일

🔢 정수의 비트 표현

Java Spring Boot
Cover Image

🔢 정수의 비트 표현

컴퓨터는 모든 숫자를 0과 1로만 저장합니다

🎯 핵심 개념

컴퓨터는 2진수(Binary)만 이해합니다


📊 10진수 vs 2진수

10진수 (Decimal, Base-10)

기본 원리: 10의 거듭제곱

5,028 (10진수)
= 5×10³ + 0×10² + 2×10¹ + 8×10⁰
= 5×1000 + 0×100 + 2×10 + 8×1
= 5000 + 0 + 20 + 8
= 5,028

자릿수:

천의 자리  백의 자리  십의 자리  일의 자리
   10³       10²       10¹       10⁰
  1000       100        10         1
    5         0         2         8

2진수 (Binary, Base-2)

기본 원리: 2의 거듭제곱

1001110100100 (2진수) = 5,028 (10진수)

= 1×2¹² + 0×2¹¹ + 0×2¹⁰ + 1×2⁹ + 1×2⁸ + 1×2⁷ + 0×2⁶ + 1×2⁵ + 0×2⁴ + 0×2³ + 1×2² + 0×2¹ + 0×2⁰
= 1×4096 + 0×2048 + 0×1024 + 1×512 + 1×256 + 1×128 + 0×64 + 1×32 + 0×16 + 0×8 + 1×4 + 0×2 + 0×1
= 4096 + 512 + 256 + 128 + 32 + 4
= 5,028

자릿수 (2의 거듭제곱):

2¹²  2¹¹  2¹⁰  2⁹  2⁸  2⁷  2⁶  2⁵  2⁴  2³  2²  2¹  2⁰
4096 2048 1024 512 256 128  64  32  16   8   4   2   1
  1    0    0   1   1   1   0   1   0   0   1   0   0

💻 Java에서의 비트 표현

Java의 정수 타입

타입크기비트 수범위 (부호 있음)
byte1 byte8 bits-128 ~ 127
short2 bytes16 bits-32,768 ~ 32,767
int4 bytes32 bits-2,147,483,648 ~ 2,147,483,647
long8 bytes64 bits-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

코드 예제

public class BinaryExample {
    public static void main(String[] args) {
        // 10진수 → 2진수 변환
        int decimal = 5028;
        String binary = Integer.toBinaryString(decimal);
        System.out.println("10진수: " + decimal);
        System.out.println("2진수: " + binary);
        // 출력: 1001110100100

        // 2진수 → 10진수 변환
        String binaryStr = "1001110100100";
        int decimalValue = Integer.parseInt(binaryStr, 2);
        System.out.println("2진수: " + binaryStr);
        System.out.println("10진수: " + decimalValue);
        // 출력: 5028

        // 리터럴로 2진수 직접 사용
        int num = 0b1001110100100;  // 0b 접두사
        System.out.println(num);  // 5028

        // 16진수 (0x 접두사)
        int hex = 0x13A4;  // 16진수
        System.out.println(hex);  // 5028
    }
}

📏 비트 수와 표현 범위

비트 수별 표현 가능한 양수 범위

비트 수표현 가능한 값의 개수범위 (0부터)
1 bit2¹ = 20 ~ 1
2 bits2² = 40 ~ 3
3 bits2³ = 80 ~ 7
4 bits2⁴ = 160 ~ 15
8 bits2⁸ = 2560 ~ 255
16 bits2¹⁶ = 65,5360 ~ 65,535
32 bits2³² = 4,294,967,2960 ~ 4,294,967,295

공식

n 비트로 표현 가능한 값의 개수 = 2ⁿ
범위: 0 ~ (2ⁿ - 1)

🔍 MSB와 LSB

용어 정의

  MSB                                    LSB
   ↓                                      ↓
[1][0][0][1][1][1][0][1][0][0][1][0][0]
 │                                       │
최상위 비트                          최하위 비트
(Most Significant Bit)        (Least Significant Bit)

MSB (Most Significant Bit):

LSB (Least Significant Bit):

실무 활용 예제

public class BitPosition {
    public static void main(String[] args) {
        int num = 5028;  // 1001110100100

        // LSB 확인 (홀수/짝수 판별)
        boolean isOdd = (num & 1) == 1;
        System.out.println("홀수? " + isOdd);  // false (짝수)

        // MSB 확인 (부호 비트)
        int msb = num >>> 31;  // 32비트에서 최상위 비트
        System.out.println("MSB: " + msb);  // 0 (양수)

        // 특정 비트 위치 확인
        int position = 2;  // 2²의 자리
        boolean bitSet = ((num >> position) & 1) == 1;
        System.out.println(position + "번째 비트: " + bitSet);
    }
}

🔄 10진수 ↔ 2진수 변환

10진수 → 2진수 (수동 계산)

5,028을 2진수로 변환:

5028 ÷ 2 = 2514 ... 0  (LSB)
2514 ÷ 2 = 1257 ... 0
1257 ÷ 2 =  628 ... 1
 628 ÷ 2 =  314 ... 0
 314 ÷ 2 =  157 ... 0
 157 ÷ 2 =   78 ... 1
  78 ÷ 2 =   39 ... 0
  39 ÷ 2 =   19 ... 1
  19 ÷ 2 =    9 ... 1
   9 ÷ 2 =    4 ... 1
   4 ÷ 2 =    2 ... 0
   2 ÷ 2 =    1 ... 0
   1 ÷ 2 =    0 ... 1  (MSB)

역순으로 읽기: 1001110100100

2진수 → 10진수 (수동 계산)

1001110100100 (2진수)

= 1×4096 + 0×2048 + 0×1024 + 1×512 + 1×256 + 1×128 + 0×64 + 1×32 + 0×16 + 0×8 + 1×4 + 0×2 + 0×1
= 4096 + 512 + 256 + 128 + 32 + 4
= 5,028

Java 코드로 변환

public class BinaryConverter {

    // 10진수 → 2진수 (직접 구현)
    public static String decimalToBinary(int decimal) {
        if (decimal == 0) return "0";

        StringBuilder binary = new StringBuilder();
        int num = decimal;

        while (num > 0) {
            binary.insert(0, num % 2);  // 나머지를 앞에 추가
            num /= 2;
        }

        return binary.toString();
    }

    // 2진수 → 10진수 (직접 구현)
    public static int binaryToDecimal(String binary) {
        int decimal = 0;
        int length = binary.length();

        for (int i = 0; i < length; i++) {
            if (binary.charAt(length - 1 - i) == '1') {
                decimal += Math.pow(2, i);
            }
        }

        return decimal;
    }

    public static void main(String[] args) {
        // 테스트
        int num = 5028;
        String binary = decimalToBinary(num);
        System.out.println(num + " → " + binary);

        int result = binaryToDecimal(binary);
        System.out.println(binary + " → " + result);

        // Java 내장 메서드 사용
        System.out.println(Integer.toBinaryString(num));
        System.out.println(Integer.parseInt(binary, 2));
    }
}

🎨 리딩 제로 (Leading Zeros)

개념

13비트: 1001110100100
16비트: 0001001110100100  (앞에 0 3개 추가)
32비트: 00000000000000000001001110100100  (앞에 0 19개 추가)

특징:

실무 예제

public class LeadingZeros {
    public static void main(String[] args) {
        int num = 5028;

        // 32비트 전체 표현 (리딩 제로 포함)
        String binary32 = String.format("%32s",
            Integer.toBinaryString(num)).replace(' ', '0');
        System.out.println("32비트: " + binary32);

        // 16비트로 제한 (앞부분 잘림)
        String binary16 = String.format("%16s",
            Integer.toBinaryString(num)).replace(' ', '0');
        System.out.println("16비트: " + binary16);

        // 리딩 제로 개수 확인
        int leadingZeros = Integer.numberOfLeadingZeros(num);
        System.out.println("리딩 제로: " + leadingZeros);  // 19개
    }
}

💡 실무 활용 사례

1️⃣ 비트 플래그 (권한 관리)

public class Permission {
    // 각 권한을 비트로 표현
    public static final int READ   = 1;  // 0001
    public static final int WRITE  = 2;  // 0010
    public static final int EXECUTE = 4;  // 0100
    public static final int DELETE = 8;  // 1000

    public static void main(String[] args) {
        // 권한 조합 (비트 OR)
        int userPermission = READ | WRITE;  // 0011 = 3

        // 권한 확인 (비트 AND)
        boolean canRead = (userPermission & READ) != 0;
        boolean canWrite = (userPermission & WRITE) != 0;
        boolean canExecute = (userPermission & EXECUTE) != 0;

        System.out.println("읽기: " + canRead);     // true
        System.out.println("쓰기: " + canWrite);    // true
        System.out.println("실행: " + canExecute);  // false

        // 권한 추가
        userPermission |= EXECUTE;  // 실행 권한 추가

        // 권한 제거
        userPermission &= ~WRITE;   // 쓰기 권한 제거
    }
}

2️⃣ 비트마스킹 (데이터 추출)

public class BitMasking {
    public static void main(String[] args) {
        // RGB 색상을 int로 저장 (ARGB 형식)
        int color = 0xFF5733;  // 빨강: FF, 녹색: 57, 파랑: 33

        // 각 색상 성분 추출
        int red   = (color >> 16) & 0xFF;  // 상위 8비트
        int green = (color >> 8) & 0xFF;   // 중간 8비트
        int blue  = color & 0xFF;          // 하위 8비트

        System.out.println("Red: " + red);     // 255
        System.out.println("Green: " + green); // 87
        System.out.println("Blue: " + blue);   // 51

        // 색상 합성
        int newColor = (red << 16) | (green << 8) | blue;
        System.out.printf("Color: 0x%X%n", newColor);
    }
}

3️⃣ 효율적인 연산

public class BitwiseOptimization {
    public static void main(String[] args) {
        int n = 100;

        // 2의 거듭제곱으로 곱하기/나누기
        int multiply2 = n << 1;   // n * 2 = 200
        int multiply4 = n << 2;   // n * 4 = 400
        int divide2 = n >> 1;     // n / 2 = 50
        int divide4 = n >> 2;     // n / 4 = 25

        // 홀수/짝수 판별
        boolean isEven = (n & 1) == 0;  // 빠름
        // vs
        boolean isEven2 = n % 2 == 0;   // 느림

        // 2의 거듭제곱 확인
        boolean isPowerOfTwo = (n & (n - 1)) == 0 && n != 0;

        System.out.println("2배: " + multiply2);
        System.out.println("1/2: " + divide2);
        System.out.println("짝수? " + isEven);
    }
}

4️⃣ IP 주소 저장

public class IpAddress {
    public static void main(String[] args) {
        // IP 주소: 192.168.1.100
        int ip = (192 << 24) | (168 << 16) | (1 << 8) | 100;

        // IP 주소 추출
        int octet1 = (ip >> 24) & 0xFF;  // 192
        int octet2 = (ip >> 16) & 0xFF;  // 168
        int octet3 = (ip >> 8) & 0xFF;   // 1
        int octet4 = ip & 0xFF;          // 100

        System.out.printf("IP: %d.%d.%d.%d%n",
            octet1, octet2, octet3, octet4);
    }
}

⚠️ 오버플로우와 언더플로우

오버플로우 (Overflow)

최대값을 초과할 때 발생

public class Overflow {
    public static void main(String[] args) {
        byte max = 127;  // byte 최대값 (0111_1111)
        byte overflow = (byte) (max + 1);

        System.out.println("Max: " + max);           // 127
        System.out.println("Overflow: " + overflow); // -128 (1000_0000)

        // int 오버플로우
        int intMax = Integer.MAX_VALUE;  // 2,147,483,647
        int intOverflow = intMax + 1;
        System.out.println("Int overflow: " + intOverflow);  // -2,147,483,648
    }
}

언더플로우 (Underflow)

최소값을 벗어날 때 발생

public class Underflow {
    public static void main(String[] args) {
        byte min = -128;  // byte 최소값
        byte underflow = (byte) (min - 1);

        System.out.println("Min: " + min);              // -128
        System.out.println("Underflow: " + underflow);  // 127
    }
}

📊 다양한 진법 표현

Java에서 지원하는 진법

public class NumberSystems {
    public static void main(String[] args) {
        int decimal = 5028;

        // 2진수 (Binary)
        String binary = Integer.toBinaryString(decimal);
        System.out.println("2진수: " + binary);
        // 1001110100100

        // 8진수 (Octal)
        String octal = Integer.toOctalString(decimal);
        System.out.println("8진수: " + octal);
        // 11644

        // 16진수 (Hexadecimal)
        String hex = Integer.toHexString(decimal);
        System.out.println("16진수: " + hex);
        // 13a4

        // 리터럴로 직접 표현
        int bin = 0b1001110100100;    // 2진수
        int oct = 011644;              // 8진수 (0으로 시작)
        int hexNum = 0x13a4;           // 16진수 (0x로 시작)

        System.out.println(bin);       // 5028
        System.out.println(oct);       // 5028
        System.out.println(hexNum);    // 5028
    }
}

🎯 핵심 요약

비트와 진법

진법기수사용 숫자예시
2진수20, 11001110100100
8진수80-711644
10진수100-95028
16진수160-9, A-F13A4

Java 정수 타입

byte  (8비트)  → -128 ~ 127
short (16비트) → -32,768 ~ 32,767
int   (32비트) → -2,147,483,648 ~ 2,147,483,647
long  (64비트) → -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

핵심 공식

n비트 표현 범위: 0 ~ (2ⁿ - 1)
부호 있는 n비트: -2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1

💡 실무 팁

1️⃣ 비트 연산은 빠르다

// ✅ 빠른 방법 (비트 연산)
int double = n << 1;      // *2
int half = n >> 1;        // /2
boolean even = (n & 1) == 0;

// ❌ 느린 방법 (산술 연산)
int double = n * 2;
int half = n / 2;
boolean even = n % 2 == 0;

2️⃣ 가독성 고려

// ❌ 가독성 낮음
if ((flags & 0x04) != 0) { }

// ✅ 가독성 높음
private static final int EXECUTE = 0x04;
if ((flags & EXECUTE) != 0) { }

3️⃣ 타입 주의

// ⚠️ byte는 쉽게 오버플로우
byte b = 100;
b = (byte) (b + 50);  // -106 (오버플로우!)

// ✅ int 사용 권장
int i = 100;
i = i + 50;  // 150

🚀 마무리

"컴퓨터는 2진수로 생각합니다. 개발자는 비트를 이해해야 합니다."

Backend 개발자가 비트를 알아야 하는 이유:

비트 연산을 마스터하면 더 효율적이고 강력한 코드를 작성할 수 있습니다! 💪

← 목록으로 돌아가기