🔢 0과 1로 숫자 표현하기
💡 핵심 질문: 컴퓨터는 왜
0.1 + 0.2 == 0.3이false일까요? 이 질문의 답은 컴퓨터가 숫자를 저장하는 방식에 있습니다.
1. 2진법 — 컴퓨터의 언어
컴퓨터는 0과 1만 이해합니다. 그래서 2진법(binary) 을 사용합니다.
- 10진법: 9를 넘으면 자리올림 → 0~9, 10개의 숫자 사용
- 2진법: 1을 넘으면 자리올림 → 0~1, 2개의 숫자 사용

2진수 표기법
int decimal = 107; // 10진수 (기본)
int binary = 0b1101011; // 2진수 (0b 접두사)
int hex = 0x6B; // 16진수 (0x 접두사)
System.out.println(decimal == binary); // true (모두 같은 값 107)
System.out.println(decimal == hex); // true
☕ Java에서 2진수 활용: 비트 연산자(
&,|,^,~,<<,>>)를 사용할 때 2진수 표현이 직관적입니다. 예를 들어 권한 관리, 플래그 처리, 성능 최적화 등에서 자주 등장합니다.
2. 16진법 — 2진수의 단점을 보완하다
2진수는 치명적인 단점이 있습니다. 숫자가 너무 길어집니다.
10진수 128
2진수 10000000 ← 8자리
16진수 80 ← 2자리 ✅
그래서 컴퓨터 세계에서는 2진수 대신 16진법(hexadecimal) 을 많이 활용합니다.
16진법 체계

16진법은 숫자 15를 넘어가는 시점에 자리올림합니다. 10~15를 표현하기 위해 알파벳 A~F를 사용합니다.
| 10진수 | 2진수 | 16진수 |
|---|---|---|
| 0 | 0000 | 0 |
| 9 | 1001 | 9 |
| 10 | 1010 | A |
| 11 | 1011 | B |
| 12 | 1100 | C |
| 13 | 1101 | D |
| 14 | 1110 | E |
| 15 | 1111 | F |
| 16 | 10000 | 10 |
2진수 ↔ 16진수 빠른 변환
4비트(1니블) = 16진수 1자리가 정확히 대응됩니다.
2진수: 1101 0111
↓ ↓
16진수: D 7 → 0xD7 (10진수 215)
개발 현장에서 16진수를 쓰는 곳
// 색상 코드 (RGB)
int red = 0xFF0000;
int green = 0x00FF00;
int blue = 0x0000FF;
// 비트 마스크
int mask = 0xFF; // 하위 8비트만 추출
// 해시코드 출력 시
System.out.printf("%08X%n", obj.hashCode());
그 외에도 MAC 주소 (
A1:B2:C3:D4:E5:F6), IPv6 주소, 메모리 주소, 색상값 등 개발 전반에서 16진수가 활용됩니다.
3. 부동 소수점 — 소수를 저장하는 방법
왜 "부동(浮動)" 소수점일까?
소수점이 고정되어 있지 않고 유동적(floating)으로 이동하기 때문입니다.
123.456 = 1.23456 × 10² (소수점을 왼쪽으로 2번 이동)
= 12345.6 × 10⁻² (소수점을 오른쪽으로 2번 이동)
2진수에서도 동일한 원리로 표현합니다.
107.6640625 (10진수)
= 1101011.1010101 (2진수)
= 1.1010111010101 × 2⁶ ← 정규화 표현 (가수부 정수 = 1)
- 지수(Exponent): 소수점이 몇 칸 이동했는지 (
6) - 가수(Significand): 실제 숫자 값 (
1.1010111010101)
IEEE 754 — 표준 저장 방식
오늘날 거의 모든 컴퓨터와 언어가 따르는 소수 저장 표준입니다.

| 필드 | 역할 | 비고 |
|---|---|---|
| 부호(Sign) | 0 = 양수, 1 = 음수 | 1비트 |
| 지수(Exponent) | 소수점 이동 횟수 | 바이어스 값 더해서 저장 |
| 가수(Fraction) | 소수 부분 (1.xxx의 xxx) | 정수부 1은 생략 |
107.6640625를 32비트로 저장하는 과정
Step 1. 2진수 변환
107.6640625 → 1101011.1010101(₂)
Step 2. 정규화 (가수부 정수 = 반드시 1)
1101011.1010101 → 1.1010111010101 × 2⁶
Step 3. 가수 저장 (정수부 1 생략, 23비트 패딩)
1010111010101 → 10101110101010000000000
Step 4. 지수 저장 (바이어스 127 더하기)
6 + 127 = 133 → 10000101(₂)
Step 5. 최종 32비트 조합
[0] [10000101] [10101110101010000000000]
↑ ↑ ↑
부호 지수(133) 가수(소수부분)
최종 비트: 0 10000101 10101110101010000000000
16진수: 42 D7 54 00
실제로 확인해보면?
import struct print(struct.pack('>f', 107.6640625).hex()) # 출력: 42d75400 ✅
4. 부동 소수점 오차 — 왜 0.1 + 0.2 ≠ 0.3 인가
문제 확인
double a = 0.1;
double b = 0.2;
double c = 0.3;
System.out.println(a + b == c); // false ❗
System.out.println(a + b); // 0.30000000000000004
Java뿐 아니라 Python, JavaScript, C/C++ 모두 동일합니다.
왜 이런 오차가 생길까?
핵심은 "10진수 소수가 항상 2진수로 딱 떨어지지 않는다" 는 점입니다.
1/3 → 10진수로 표현 → 0.3333... (무한 반복, 딱 안 떨어짐)
0.1 → 2진수로 표현 → 0.0001100110011... (무한 반복, 딱 안 떨어짐!)
메모리는 유한하기 때문에 무한히 반복되는 소수를 어느 지점에서 잘라버립니다. 이 잘린 부분이 바로 부동 소수점 오차의 원인입니다.
실제로 저장된 0.1 → 0.1000000000000000055511151231257827021181583404541015625
실제로 저장된 0.2 → 0.200000000000000011102230246251565404236316680908203125
합계 → 0.3000000000000000444089209850062616169452667236328125
≠ 0.3 !!!
Java에서 오차 없이 소수 다루기
① BigDecimal 사용 (가장 정확)
import java.math.BigDecimal;
BigDecimal a = new BigDecimal("0.1"); // 문자열로 생성해야 정확!
BigDecimal b = new BigDecimal("0.2");
BigDecimal c = new BigDecimal("0.3");
System.out.println(a.add(b).equals(c)); // true ✅
System.out.println(a.add(b)); // 0.3 ✅
② 허용 오차 범위 비교 (epsilon 비교)
double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 1e-9; // 허용 오차
System.out.println(Math.abs(a - b) < epsilon); // true ✅
③ 정수로 변환 후 계산
// 금액 계산: 원 단위로 변환 후 계산
long priceInCents = 1099; // 10.99원을 1099로 저장
long taxInCents = 88; // 0.88원을 88로 저장
long totalCents = priceInCents + taxInCents; // 1187
double total = totalCents / 100.0; // 11.87
⚠️ 실무 주의사항: 금융 계산, 세금, 정밀 측정값 등에서는 반드시
BigDecimal또는 정수 연산을 사용하세요.double로 금액 계산을 하면 원단위 오차가 발생할 수 있습니다.
5. 핵심 요약
컴퓨터의 숫자 표현
10진수 ──변환──► 2진수 (0b...) ← CPU가 실제로 사용
──변환──► 16진수 (0x...) ← 사람이 읽기 편하게 축약
소수 ──IEEE 754──► [부호 1bit | 지수 8or11bit | 가수 23or52bit]
↑
무한 소수는 잘라서 저장 → 오차 발생!
| 진법 | 특징 | 사용 예 |
|---|---|---|
| 2진수 | CPU가 이해하는 언어 | 비트 연산, 논리 처리 |
| 16진수 | 2진수 4자리 = 1자리로 압축 | 색상, 메모리 주소, MAC |
| 부동 소수점 | IEEE 754, 소수 저장 방식 | float(32bit), double(64bit) |
| BigDecimal | 정밀한 10진 소수 계산 | 금융, 세금 계산 |