문서 읽는 데 44분 · A1

A-1: 컴퓨터의 구성과 데이터 표현

목차 36
전체 12강 중 1강 · CS 기초지식
난이도 · 중급

ℹ️컴퓨터 구조·운영체제·네트워크 — 언어 밑에 깔린 원리와 기술 면접 CS 질문 대비. 코딩에 어느 정도 익숙해진 뒤가 좋아요.

안녕하세요! 여러분의 CS 길잡이, 홍순구 튜터입니다.

드디어 컴퓨터 과학(CS, Computer Science) 기초의 막을 올립니다. 여러분은 지금까지 변수에 값을 담고, 반복문을 돌리고, 함수를 호출하는 코드를 써봤을 거예요. 그런데 한 번이라도 이런 생각, 해본 적 있나요?

"내가 방금 int age = 25; 라고 적은 이 한 줄은, 컴퓨터 안에서 실제로 어떻게 저장되고 처리되는 걸까?"

우리가 키보드로 두드린 코드는 사람이 읽으라고 만든 글자일 뿐입니다. 컴퓨터는 그 글자를 모릅니다. 컴퓨터가 아는 건 오직 켜짐과 꺼짐, 그러니까 0과 1 두 가지뿐이에요. 그 두 가지로 숫자도 만들고, 한글도 만들고, 사진도 만들고, 결국 여러분의 프로그램 전체가 돌아갑니다. 오늘은 그 "한 겹 아래"의 세계로 처음 내려가 봅니다.

본격적으로 들어가기 전에, 실제 기술 면접에서 자주 나오는 질문 하나를 미리 보여드릴게요. 여러분이 평소 쓰는 어떤 언어든 좋으니, 머릿속으로 0.1 + 0.2 의 결과를 떠올려보세요. 당연히 0.3 이겠죠? 그런데 실제로 실행하면 이렇게 나옵니다.

텍스트
>>> 0.1 + 0.2
0.30000000000000004

처음 보면 "컴퓨터가 고장 났나?" 싶습니다. 하지만 이건 버그가 아니라, 컴퓨터가 실수(소수)를 0과 1로 표현하는 방식 때문에 반드시 생기는 현상이에요. 면접관이 "왜 이런 결과가 나올까요?" 라고 물었을 때, "글쎄요…" 하고 막히는 사람과 "컴퓨터가 0.1을 2진수로 정확히 표현하지 못해서요" 라고 한 호흡에 답하는 사람. 이 한 줄에서 기초가 있는 사람과 없는 사람이 갈립니다. 오늘 수업이 끝나면 여러분은 후자가 됩니다.

오늘은 CS 기초 과목의 첫 시간이니, 앞으로 우리가 함께 오를 산 전체를 한눈에 보고 가겠습니다. 큰 줄기는 네 개의 기둥이에요.

텍스트
A. 컴퓨터 구조  내 코드가 도는 하드웨어 — CPU·메모리·0과 1   ◀ 지금 여기
   │
B. 운영체제     그 위에서 자원을 나눠 주는 관리자 — 프로세스·스레드·메모리
   │
C. 네트워크     컴퓨터끼리 대화하는 법 — TCP·HTTP·"URL 치면 일어나는 일"
   │
D. 면접 기초    이웃 분야의 핵심만 — DB·자료구조를 면접 앵글로
   │
E. 면접 종합    네 기둥을 한 문장으로 엮어 면접장에서 말하기

일부러 안쪽(하드웨어)에서 바깥(네트워크)으로 넓혀 갑니다. CPU와 메모리(A)를 알아야 그 위에서 운영체제가 메모리를 나눠 쓰는 방식(B)이 와닿고, 컴퓨터 한 대 안의 동작(B)을 알아야 여러 대를 잇는 네트워크(C)가 막히지 않거든요. 그리고 그 모든 길목마다 기술 면접 단골 질문이 숨어 있어서, 각 개념 끝에 "면접에서 이렇게 답하라"를 콕 집어 드릴 거예요.

그 네 기둥의 가장 밑바닥, 모든 것이 시작되는 0과 1의 세계가 바로 오늘 A-1입니다. 오늘 우리는 코드를 짜지 않습니다. 대신 여러분이 매일 짜는 코드가 발을 딛고 선 가장 단단한 바닥을 들여다봅니다. 이 바닥을 한 번 제대로 보고 나면, 앞으로 만나는 모든 버그·성능 문제·면접 질문이 한 겹 더 선명하게 보일 거예요.

💡 오늘 수업의 핵심 — "컴퓨터는 0과 1만 다루고, 그 0과 1로 음수·소수·한글까지 표현한다" 🎯

🎯 학습 목표

  • 컴퓨터의 5대 구성요소폰노이만 구조(프로그램 내장 방식)를 이해하고, "소프트웨어만 바꿔도 다른 일을 하는" 컴퓨터의 본질을 설명합니다.
  • 2진수·16진수2의 보수(음수 표현)로 컴퓨터가 정수를 다루는 방식을 잡고, 면접 단골인 "2의 보수가 뭔가요"에 원리로 답합니다.
  • 부동소수점(IEEE 754)으로 0.1 + 0.2 ≠ 0.3 의 정체를 밝히고, 문자 인코딩(ASCII·유니코드·UTF-8)으로 한글 'ㄱ'이 0과 1이 되는 과정을 설명합니다.

Step 1: "컴퓨터는 사실 5개의 부품이에요"

데스크톱, 노트북, 스마트폰, 서버, 게임기. 겉모습은 천차만별이지만 안을 열어보면 놀랍게도 딱 다섯 종류의 핵심 부품으로 정리됩니다. 이 다섯이 무엇인지 먼저 잡고 가죠.

  1. CPU(중앙처리장치, Central Processing Unit) — 실제로 계산하고 판단하는 두뇌
  2. 주기억장치(메인 메모리, Main Memory) — 실행 중인 프로그램과 데이터가 잠깐 머무는 곳. 흔히 RAM
  3. 보조기억장치(Secondary Storage) — 전원이 꺼져도 남는 영구 저장소. SSD나 HDD
  4. 입출력장치(I/O Device) — 사람·바깥세상과 데이터를 주고받는 통로. 키보드·마우스(입력), 모니터·프린터(출력)
  5. 버스(Bus) — 위 부품들 사이로 0과 1이 오가는 길

용어만 늘어놓으면 잘 안 와닿으니, 작은 사무실 하나로 비유해 볼게요.

텍스트
   사무실(컴퓨터)에 빗대면

   CPU         일하는 직원      — 실제로 계산하고 판단한다
   주기억(RAM)  책상 위         — 지금 펼쳐 놓고 작업 중인 서류 (넓을수록 한 번에 많이 펼침)
   보조기억(SSD) 서류 캐비닛      — 안 쓰는 서류를 넣어두는 곳 (퇴근해도 남지만 꺼내오기 느림)
   입출력(I/O)  사무실 문·창구   — 바깥과 서류를 주고받는다
   버스(Bus)    복도            — 직원이 책상·캐비닛·창구를 오가는 길

이 부품들이 실제로 어떻게 연결돼 있는지 그림으로 보면 이렇습니다. CPU가 위에 있고, 버스라는 큰 길이 가운데를 가로지르며, 거기에 메모리·입출력·저장장치가 매달려 있는 모양이에요.

텍스트
              ┌───────────────┐
              │      CPU      │   ── 중앙처리장치 : 연산과 제어를 맡은 두뇌
              └───────┬───────┘
                      │
   ═══════════════════╪═══════════════════   ◀ Bus(버스) : 부품 사이로 0과 1이 오가는 통로
          ┌───────────┼───────────┐
          │           │           │
   ┌──────┴────┐ ┌────┴─────┐ ┌───┴───────┐
   │  Memory   │ │   I/O    │ │  Storage  │
   └───────────┘ └──────────┘ └───────────┘
     주기억장치     입출력장치    보조기억장치
     (RAM)        (키보드·모니터) (SSD·HDD)

여기서 초보자가 가장 헷갈리는 한 쌍이 주기억장치(RAM)와 보조기억장치(SSD)입니다. "둘 다 데이터를 저장하는 거 아니야?" 싶지만, 결정적인 차이가 두 가지 있어요. 속도휘발성입니다. RAM은 아주 빠르지만 전원이 꺼지면 내용이 싹 사라지고(휘발성), SSD는 상대적으로 느리지만 전원이 꺼져도 남습니다(비휘발성). 그래서 평소엔 캐비닛(SSD)에 넣어두고, 작업할 때만 책상(RAM) 위에 펼쳐 놓는 거예요.

🙋 학생 질문 — "RAM이 그렇게 빠르고 좋으면, 그냥 RAM만 엄청 크게 쓰면 안 되나요? SSD는 왜 필요해요?"

날카로운 질문이에요! 두 가지 이유 때문입니다.

첫째, 휘발성. RAM은 전원이 꺼지면 내용이 전부 사라집니다. 만약 사진과 문서를 RAM에만 저장한다면, 컴퓨터를 끄는 순간 전부 증발해 버려요. 영구 보관이 불가능하죠.

둘째, 가격. 같은 용량이라도 RAM이 SSD보다 훨씬 비쌉니다. 그래서 "빠르지만 비싸고 휘발성인 RAM"은 작게 쓰고, "느리지만 싸고 영구적인 SSD"는 크게 씁니다. 이렇게 성격이 다른 저장 공간을 역할에 맞게 나눠 쓰는 발상은 다음 시간(A-2)에 배울 "메모리 계층 구조"의 씨앗이기도 해요.

🎯 면접에서는 이렇게 답하세요

"주기억장치(RAM)와 보조기억장치(SSD)의 가장 큰 차이는 휘발성과 속도입니다. RAM은 전원이 꺼지면 내용이 사라지는 휘발성 메모리지만 매우 빠르고, SSD는 전원이 꺼져도 남는 비휘발성 저장장치지만 상대적으로 느립니다. 그래서 실행 중인 프로그램은 빠른 RAM에 올려두고, 영구 보관할 파일은 SSD에 저장합니다."

💡 다섯 부품 중 오늘 우리가 집중할 주인공은 CPU와 메모리입니다. 이 둘이 0과 1을 주고받으며 일하는 방식이 바로 모든 컴퓨터의 공통 설계도, 다음 Step의 "폰노이만 구조"예요.


Step 2: "모든 컴퓨터의 설계도 — 폰노이만 구조"

질문 하나 드릴게요. 지금 여러분이 쓰는 노트북 한 대로 게임도 하고, 영상도 보고, 코딩도 하죠? 하드웨어는 똑같은데 어떻게 이렇게 다른 일을 할 수 있을까요? 너무 당연해 보이지만, 사실 이건 컴퓨터 역사에서 엄청난 발명이었습니다.

초창기 컴퓨터(에니악, ENIAC)는 그렇지 못했어요. 새로운 계산을 시키려면 전선을 일일이 다시 꽂아야 했습니다. 곱셈 기계를 덧셈 기계로 바꾸려면 며칠씩 배선 작업을 했죠. 하드웨어 자체가 곧 프로그램이었으니까요.

이 불편함을 풀어낸 천재적인 아이디어가 바로 폰노이만 구조(von Neumann architecture)입니다. 핵심은 한 문장이에요.

"명령어(프로그램)도 데이터처럼 숫자로 바꿔서, 메모리에 함께 저장하자."

이걸 프로그램 내장 방식(stored-program)이라고 부릅니다. 프로그램이 메모리 안에 숫자로 들어가 있으니, 전선을 다시 꽂을 필요 없이 메모리에 올리는 내용만 바꾸면 컴퓨터가 전혀 다른 일을 합니다.

요리책으로 비유하면 딱 맞아요. 주방(하드웨어)은 그대로 두고, 요리책(프로그램)만 바꿔 끼우는 거예요. 김치찌개 책을 펴면 김치찌개를 만들고, 파스타 책을 펴면 파스타를 만듭니다. 요리가 바뀐다고 주방을 뜯어고치지 않죠. 컴퓨터도 똑같습니다.

그럼 CPU는 메모리에 저장된 그 명령어들을 어떻게 처리할까요? 아주 단순한 동작을 쉬지 않고 반복합니다.

텍스트
   ┌──────────────────────────────┐
   │            Memory            │  ◀ 하나의 메모리 안에
   │   [ instructions | data ]    │     명령어(instructions)와
   └───────────────┬──────────────┘     데이터(data)가 함께 산다
                   │
        ① Fetch   │   명령어 하나를 메모리에서 꺼낸다
                   ▼
   ┌──────────────────────────────┐
   │             CPU              │
   └──────────────────────────────┘
        ② Decode  : 꺼낸 명령어를 해석한다
        ③ Execute : 해석한 대로 실행한다
              └──▶ 다시 ①로 돌아가 다음 명령어를 꺼낸다

꺼내고(Fetch) → 해석하고(Decode) → 실행하고(Execute) → 다시 꺼내고. CPU는 1초에 이 과정을 수십억 번 반복합니다. 이 반복을 명령어 사이클(instruction cycle)이라고 부르는데, 이건 다음 시간(A-2)에서 CPU 내부를 들여다보며 자세히 다룰 거예요. 오늘은 "CPU가 메모리에서 명령어를 하나씩 꺼내 순서대로 실행한다"는 큰 그림만 잡으면 충분합니다.

🙋 학생 질문 — "명령어랑 데이터를 같은 메모리에 섞어 두면, 컴퓨터가 둘을 어떻게 구분해요?"

정말 좋은 질문이에요. 메모리 안에서는 명령어든 데이터든 똑같이 0과 1의 나열일 뿐이라, 생긴 것만 봐서는 구분이 안 됩니다.

비결은 "언제 읽느냐"예요. CPU가 Fetch 단계에서 읽어 온 값은 명령어로 해석하고, Execute 단계에서 그 명령어가 가리키는 값을 읽으면 데이터로 다룹니다. 즉 같은 0과 1이라도 CPU가 어느 단계에서 어떤 의도로 읽느냐에 따라 명령어가 되기도 하고 데이터가 되기도 합니다.

참고로 명령어와 데이터를 아예 다른 메모리로 분리한 설계(하버드 구조)도 있지만, 우리가 쓰는 일반적인 컴퓨터는 대부분 둘을 한 메모리에 두는 폰노이만 구조예요.

🎯 면접에서는 이렇게 답하세요

"폰노이만 구조의 핵심은 프로그램 내장 방식입니다. 명령어를 데이터와 똑같이 메모리에 저장하기 때문에, 하드웨어를 바꾸지 않고 메모리에 올리는 프로그램만 교체하면 컴퓨터가 전혀 다른 일을 할 수 있습니다. 우리가 같은 노트북으로 게임도 하고 코딩도 하는 게 바로 이 구조 덕분이고, CPU는 메모리의 명령어를 꺼내고(Fetch)·해석하고(Decode)·실행하는(Execute) 과정을 반복하며 동작합니다."

💡 폰노이만 구조 덕분에 프로그램도 결국 메모리 속 숫자라는 걸 알았습니다. 그렇다면 그 숫자는 대체 어떻게 생겼을까요? 왜 하필 0과 1일까요? 다음 Step에서 컴퓨터가 0과 1만 고집하는 진짜 이유를 파헤쳐 봅니다.


Step 3: "컴퓨터는 왜 0과 1만 쓸까"

앞에서 계속 "컴퓨터는 0과 1만 안다"고 했죠. 그런데 왜 하필 0과 1일까요? 우리처럼 0부터 9까지 열 개 숫자(10진수)를 쓰면 더 편할 텐데 말이에요.

답은 컴퓨터의 몸속에 있습니다. 컴퓨터는 결국 전기로 돌아가는 기계예요. 그리고 전기가 가장 확실하게 구분할 수 있는 상태는 딱 두 가지입니다. 전기가 흐른다(켜짐), 안 흐른다(꺼짐).

비유하면 전구 스위치와 같아요. 스위치는 켜짐(ON)과 꺼짐(OFF) 두 상태가 분명합니다. "75% 정도 켜짐" 같은 애매한 상태를 만들려면 회로가 훨씬 복잡해지고 오류도 잘 나죠. 그래서 컴퓨터는 가장 단순하고 확실한 두 상태, 즉 0(꺼짐)과 1(켜짐) 만 쓰기로 한 거예요. 이렇게 0과 1 두 개의 숫자만으로 수를 표현하는 방식을 2진법(binary)이라고 합니다.

비트와 바이트 — 정보의 기본 단위

이 0 또는 1 하나하나를 비트(bit, binary digit)라고 부릅니다. 컴퓨터가 다루는 가장 작은 정보 단위예요. 비트 하나는 0 아니면 1, 두 가지만 표현할 수 있습니다.

그런데 비트 하나로는 표현할 수 있는 게 너무 적죠. 그래서 비트 8개를 묶어 한 덩어리로 다루는데, 이걸 바이트(byte)라고 합니다. 비트 8개면 2의 8제곱, 즉 256가지(0~255)를 표현할 수 있어요.

단위 크기 표현 가능 수
비트(bit) 0 또는 1 2가지
바이트(byte) 8비트 256가지

2진수는 어떻게 읽을까

10진수 253을 떠올려봅시다. 이건 사실 각 자리가 10의 거듭제곱이라는 약속이에요. 2 × 100 + 5 × 10 + 3 × 1 인 거죠. 2진수도 똑같은 원리인데, 자릿값이 10의 거듭제곱이 아니라 2의 거듭제곱일 뿐입니다.

텍스트
   2진수    1   1   0   1
   자릿값   8   4   2   1     (각 자리는 2의 거듭제곱: 8=2³, 4=2², 2=2¹, 1=2⁰)
            │   │   │   │
            8 + 4 + 0 + 1  =  13   (10진수)

2진수 1101을 읽어보면 8 + 4 + 0 + 1 = 13입니다. 자리마다 켜진(1) 자릿값만 더하면 끝이에요. 어렵지 않죠?

16진수 — 사람을 위한 속기

2진수는 컴퓨터에겐 완벽하지만, 사람이 보기엔 너무 깁니다. 숫자가 조금만 커져도 11010110처럼 0과 1이 줄줄이 늘어져 읽기도 옮겨 적기도 힘들죠.

그래서 사람이 편하게 보려고 만든 게 16진법(hexadecimal)입니다. 0~9 다음에 A, B, C, D, E, F를 더 써서 16개 기호로 수를 표현해요. (A=10, B=11, ... F=15) 16진수의 진짜 강점은 2진수 4비트가 16진수 1자리에 딱 맞아떨어진다는 거예요. 4비트로 표현할 수 있는 게 16가지, 16진수 한 자리도 16가지니까요.

텍스트
   2진수    1101  0110
                         4비트씩 끊어서
   16진수    D     6          0xD6

그래서 길고 복잡한 2진수도 16진수로 적으면 1/4 길이로 짧아집니다. 색상 코드(#FF0000), 메모리 주소(0x7ffe...) 같은 데서 16진수를 만나는 이유가 이거예요. 컴퓨터가 쓰는 2진수를 사람이 읽기 좋게 압축한 속기인 셈입니다.

🎯 면접에서는 이렇게 답하세요

"컴퓨터가 2진수를 쓰는 이유는 전기 신호의 켜짐·꺼짐 두 상태로 데이터를 가장 확실하게 표현할 수 있기 때문입니다. 중간 상태 없이 0과 1만 구분하면 회로가 단순하고 노이즈에 강합니다. 16진수는 그 긴 2진수를 사람이 읽기 쉽게 줄인 표기로, 2진수 4비트가 16진수 한 자리에 정확히 대응해서 메모리 주소나 색상 코드를 표현할 때 자주 씁니다."

💡 0과 1로 양의 정수는 표현했습니다. 그런데 -5 같은 음수는요? 0과 1만 있는 세상엔 마이너스 기호(-)조차 없는데 말이에요. 다음 Step에서 컴퓨터가 음수를 다루는 영리한 방법을 봅니다.


Step 4: "마이너스는 어떻게? — 2의 보수"

0과 1로 양의 정수는 표현했습니다. 그런데 -5 같은 음수는 어떻게 할까요? 0과 1만 있는 세상에는 마이너스 기호(-)가 없습니다. 부호조차 0과 1로 표현해야 해요.

가장 단순한 발상은 "맨 앞 비트 하나를 부호 전용으로 쓰자"입니다. 0이면 양수, 1이면 음수로요. 이걸 부호-크기 방식이라 하는데, 문제가 두 가지 있어요. 첫째, +0과 -0이 따로 생깁니다(00001000). 0이 두 개라니 이상하죠. 둘째, 덧셈·뺄셈 회로가 복잡해집니다. 그래서 거의 모든 컴퓨터는 더 영리한 방법인 2의 보수(two's complement)를 씁니다.

시계로 이해하는 2의 보수

2의 보수의 핵심 아이디어는 시계에 있습니다. 지금이 9시인데 3시간 전으로 돌리고 싶어요. 두 가지 방법이 있죠.

  • 시계를 거꾸로 3칸 돌린다: 9 - 3 = 6시
  • 시계를 앞으로 9칸 돌린다: 9 + 9 = 18 → 한 바퀴(12)를 넘으면 6시

신기하게 빼기(-3) 대신 더하기(+9) 로도 같은 결과(6시)가 나옵니다. 12를 한 바퀴로 치고 넘어가는 부분을 버리면 되니까요. 2의 보수가 바로 이 원리예요. 음수를 "더하면 뺄셈이 되는 어떤 양수"로 바꿔서, 컴퓨터가 뺄셈 회로 없이 덧셈만으로 모든 계산을 하게 만듭니다.

-5를 만드는 법 — 비트 반전 후 +1

8비트(1바이트)로 -5를 표현해 볼게요. 만드는 법은 딱 두 단계입니다.

텍스트
   5  =  0000 0101      ① 양수 5의 2진수
         1111 1010      ② 비트 반전 (01 모두 뒤집기)
       +         1      ③ 1을 더한다
       ──────────────
         1111 1011   =  -5

이렇게 만든 1111 1011이 -5입니다. 진짜인지 검산해 볼까요? 5 + (-5)는 0이어야 하죠.

텍스트
     0000 0101   (  5)
   + 1111 1011   ( -5)
   ─────────────
   1 0000 0000     맨 앞 올림(9번째 비트)은 버린다    0000 0000 = 0

8비트 범위를 넘어간 맨 앞 자리(올림)를 버리면 정확히 0이 됩니다. 시계가 12를 넘으면 버린 것과 똑같죠. 이 방식의 두 가지 큰 장점이 면접 포인트예요. 첫째, 뺄셈을 따로 만들 필요가 없습니다. A - BA + (-B)로, 즉 덧셈 회로 하나로 다 처리합니다. 둘째, 0이 딱 하나뿐입니다. 부호-크기 방식의 골칫거리였던 +0/-0 문제가 사라져요.

🙋 학생 질문 — "맨 앞 비트가 1이면 무조건 음수인가요?"

네, 2의 보수에서는 맨 왼쪽 비트(최상위 비트)가 부호 역할을 합니다. 0이면 양수(또는 0), 1이면 음수예요.

그래서 8비트로는 -128 ~ +127까지 표현합니다. 양수 쪽은 127까지인데 음수 쪽은 -128까지라 살짝 비대칭이죠? 이건 0이 양수 쪽(0000 0000)에 한 자리를 차지하기 때문이에요. 일반화하면 n비트의 표현 범위는 -2ⁿ⁻¹ ~ +(2ⁿ⁻¹ - 1) 입니다. 예컨대 우리가 흔히 쓰는 32비트 정수(int)의 범위가 약 -21억 ~ +21억인 것도 같은 원리예요.

🎯 면접에서는 이렇게 답하세요

"컴퓨터가 음수를 표현하는 표준 방식은 2의 보수입니다. 어떤 수의 모든 비트를 반전한 뒤 1을 더하면 그 수의 음수가 됩니다. 핵심 장점은 두 가지인데, 뺄셈을 별도 회로 없이 덧셈만으로 처리할 수 있고, 부호-크기 방식과 달리 0이 하나로 유일하다는 점입니다. 그래서 +0과 -0이 따로 생기는 문제가 없습니다."

💡 정수(양수·음수)는 끝났습니다. 그런데 소수점이 있는 실수(0.1, 3.14)는 어떻게 표현할까요? 바로 여기서 오프닝에 던졌던 그 악명 높은 0.1 + 0.2 문제가 터집니다. 다음 Step에서 정체를 밝혀봅시다.


Step 5: "0.1 + 0.2가 0.3이 아닌 이유"

드디어 오프닝에서 던졌던 그 질문으로 돌아왔습니다. 0.1 + 0.2가 왜 0.30000000000000004가 될까요? 이제 여러분은 답할 준비가 됐어요.

먼저, 10진수의 한계부터

컴퓨터를 탓하기 전에, 우리가 매일 쓰는 10진수에도 똑같은 한계가 있다는 걸 봐야 합니다. 1/3을 소수로 적어보세요. 0.333333... 끝없이 이어지죠. 10진법으로는 1/3을 유한한 자리로 정확히 적을 수 없습니다. 어딘가에서 끊어야 하고, 그 순간 약간의 오차가 생깁니다.

2진법에도 똑같은 일이 벌어집니다. 10진법에서 1/3이 안 떨어지듯, 2진법에서는 0.1이 안 떨어져요. 0.1을 2진수로 바꾸면 이렇게 됩니다.

텍스트
   0.1 (10진수)  =  0.0001100110011001100110011...  (2진수)
                         └──┬──┘
                       0011 이 영원히 반복 — 딱 떨어지지 않는다

0.1은 2진수로 무한히 반복되는 소수예요. 그런데 컴퓨터의 저장 공간은 유한하죠(보통 64비트). 그래서 어딘가에서 잘라낼 수밖에 없고, 잘린 그 값은 진짜 0.1이 아니라 "0.1에 아주 가까운 값"이 됩니다. 이렇게 미세하게 어긋난 값 두 개(0.1, 0.2)를 더하니 0.30000000000000004라는 오차가 드러난 거예요.

실수를 저장하는 법 — IEEE 754

그럼 컴퓨터는 이 실수를 비트에 어떻게 욱여넣을까요? 부동소수점(floating point)이라는 방식을 씁니다. 거의 모든 컴퓨터가 따르는 표준이 IEEE 754예요. 핵심은 실수를 세 부분으로 쪼개 저장하는 겁니다.

텍스트
   ┌─┬───────────┬────────────────────────────────┐
   │S│  Exponent │            Mantissa            │
   └─┴───────────┴────────────────────────────────┘
    1     11비트              52비트
    │       │                  │
    부호    지수(소수점 위치)    가수(유효 숫자)

비유하면 과학적 표기법(3.14 × 10²)과 같아요. 부호(+/−), 지수(소수점을 어디로 옮길지), 가수(실제 숫자 값)로 나눠 담는 거죠. 이렇게 하면 아주 크거나 작은 수도 효율적으로 표현할 수 있습니다. 다만 가수의 비트 수(52비트)가 유한하니, 무한 반복되는 0.1 같은 수는 반드시 근삿값으로 저장됩니다.

그래서 실무에서는

이게 단순한 호기심거리가 아니라 실무 버그의 단골 원인이에요. 그래서 두 가지 원칙을 꼭 기억하세요.

⚠️ 실수는 ==로 비교하지 마세요. if (0.1 + 0.2 == 0.3)은 false가 나옵니다. 대신 "두 값의 차이가 아주 작은 오차범위(epsilon) 안이면 같다고 본다"는 식으로 비교합니다.

⚠️ 돈 계산에 실수(float/double)를 쓰지 마세요. 0.1원씩 오차가 쌓이면 큰 사고가 됩니다. 금액은 정수(원 단위)나 십진 전용 타입(BigDecimal, Decimal)으로 다룹니다. (이건 생각해볼 주제에서 더 파봅니다.)

🎯 면접에서는 이렇게 답하세요

"0.1 + 0.20.3이 아닌 이유는 부동소수점의 표현 한계 때문입니다. 10진수에서 1/3이 0.333...으로 무한히 반복되듯, 2진수에서는 0.1이 무한 반복 소수가 됩니다. 컴퓨터는 유한한 비트(IEEE 754, 보통 64비트)에 저장하므로 0.1을 정확히 담지 못하고 근삿값으로 저장하고, 그 오차가 누적돼 결과가 어긋납니다. 그래서 실수는 등호로 직접 비교하지 않고 오차범위로 비교하며, 정확한 금액 계산에는 부동소수점 대신 정수나 십진 전용 타입을 씁니다."

💡 숫자(정수·실수)는 전부 0과 1로 표현했습니다. 이제 마지막 퍼즐만 남았어요. 여러분이 지금 읽는 이 글자, 특히 한글은 어떻게 0과 1이 될까요? 다음 Step에서 마무리합니다.


Step 6: "한글 'ㄱ'은 어떻게 0과 1이 되나"

숫자는 0과 1로 다 표현했습니다. 그런데 여러분이 지금 읽는 이 글자들, 'A'·'ㄱ'·'가'는요? 컴퓨터는 글자도 결국 숫자(0과 1)로 바꿔 저장합니다. 그 "글자 ↔ 숫자" 변환 약속을 문자 인코딩(character encoding)이라고 해요.

ASCII — 영어를 위한 첫 약속

가장 오래된 약속은 ASCII(아스키)입니다. 영어 알파벳·숫자·기호에 0~127번 번호를 매겼어요. 예를 들어 'A'는 65번입니다.

텍스트
   'A'    65    0100 0001    (1바이트면 충분)
   'B'    66    0100 0010
   'a'    97    0110 0001

ASCII는 0~127, 즉 128가지면 충분했습니다. 영어권에선 알파벳 대소문자 52개에 숫자·기호를 더해도 그 안에 들어갔으니까요. 문제는 세상에 영어만 있는 게 아니라는 것이었어요. 한글, 한자, 아랍어, 이모지... ASCII의 128칸으로는 어림도 없습니다.

유니코드 — 세상 모든 글자에 번호를

그래서 등장한 게 유니코드(Unicode)입니다. 핵심 발상은 간단해요. 지구상의 모든 문자에 고유 번호를 하나씩 붙이자. 한글 '가'는 U+AC00번, 'ㄱ'은 U+3131번, 이런 식으로요. 이 번호를 코드 포인트(code point)라고 부릅니다.

여기서 면접에 자주 나오는 핵심 구분이 있어요. 유니코드는 "번호표"일 뿐, "저장 방식"이 아닙니다. '가'에 AC00이라는 번호를 정한 것까지가 유니코드고, 그 번호를 실제로 0과 1로 어떻게 저장하느냐는 별도의 문제예요.

비유하면 이렇습니다. 유니코드는 전 국민에게 번호를 부여한 명부 같은 거예요. "누구는 몇 번"이라고 정한 표죠. 그런데 그 번호를 종이에 어떻게 적느냐(한 칸에? 여러 칸에 나눠서?)는 또 다른 약속입니다. 그 "적는 방법"이 바로 다음에 볼 UTF-8이에요.

UTF-8 — 유니코드 번호를 저장하는 영리한 방법

UTF-8은 유니코드 번호를 실제 바이트로 저장하는, 가장 널리 쓰이는 방식입니다. 가장 똑똑한 특징은 글자마다 차지하는 바이트 수가 다르다는 거예요.

텍스트
   'A'  (U+0041)     1바이트   01000001
   'ㄱ' (U+3131)     3바이트   11100011 10000100 10110001
   '가' (U+AC00)     3바이트   11101010 10110000 10000000
   😀   (U+1F600)    4바이트   ...

영어 알파벳(ASCII 범위)은 1바이트, 한글은 3바이트, 이모지는 4바이트로 저장됩니다. 자주 쓰는 영어는 짧게, 가끔 쓰는 글자는 길게 담아 공간을 아끼는 영리한 설계죠. 특히 영어가 1바이트라서 기존 ASCII 문서가 UTF-8과 그대로 호환됩니다. 이게 UTF-8이 사실상 표준이 된 결정적 이유예요.

이 원리를 알면, 한글 파일을 잘못된 인코딩으로 열었을 때 글자가 깨지는(���) 이유도 이해됩니다. UTF-8로 저장한 한글(3바이트)을 다른 약속으로 해석하면 엉뚱한 바이트 조합이 되어 깨지는 거예요. 그래서 웹페이지 맨 위에 <meta charset="UTF-8">을 붙입니다. "이 문서는 UTF-8 약속으로 읽어주세요"라는 뜻이죠.

🎯 면접에서는 이렇게 답하세요

"유니코드와 UTF-8은 층위가 다릅니다. 유니코드는 세상 모든 문자에 고유 번호(코드 포인트)를 부여한 표준 번호표이고, UTF-8은 그 번호를 실제 바이트로 저장하는 인코딩 방식입니다. UTF-8은 가변 길이라서 ASCII 영역(영어)은 1바이트, 한글은 3바이트, 이모지는 4바이트를 씁니다. 특히 영어가 1바이트라 기존 ASCII와 완전히 호환되는 게 UTF-8이 사실상 표준이 된 이유입니다."

💡 이제 숫자도, 글자도 전부 0과 1로 표현하는 원리를 봤습니다. 오늘 배운 걸 한 번에 정리하고, 다음 시간으로 이어갈 다리를 놓아볼게요.


마무리

오늘 배운 핵심 세 가지

🎯 하나, 컴퓨터는 5대 구성요소(CPU·주기억·보조기억·입출력·버스)로 이뤄지고, 폰노이만 구조(프로그램 내장 방식) 덕분에 하드웨어를 바꾸지 않고 소프트웨어만 교체해서 다른 일을 합니다.

🎯 , 컴퓨터는 전기의 켜짐·꺼짐 때문에 0과 1(2진법) 만 쓰고, 음수는 2의 보수(비트 반전 후 +1)로 표현해 뺄셈을 덧셈으로 처리합니다. 16진수는 긴 2진수를 줄인 사람용 속기예요.

🎯 , 실수는 부동소수점(IEEE 754)으로 저장돼 0.1 같은 값에 오차가 생기고, 글자는 문자 인코딩(유니코드는 번호표, UTF-8은 저장 방식)을 거쳐 0과 1이 됩니다.

다음 시간 예고

오늘 우리는 "컴퓨터가 무엇으로 이뤄지고, 0과 1로 무엇을 표현하는지"를 봤습니다. 그런데 큰 질문이 하나 남았어요. CPU는 그 0과 1을 대체 어떻게, 얼마나 빠르게 처리할까요?

다음 시간(A-2)에는 CPU 안으로 들어가 봅니다. 폰노이만 구조에서 살짝 맛본 명령어 사이클(꺼내고-해석하고-실행하고)을 자세히 들여다보고, 더 중요하게는 메모리 계층 구조를 만나요. CPU는 엄청나게 빠른데 메모리(RAM)는 상대적으로 느려서, 그 속도 차이 때문에 CPU가 데이터를 기다리며 노는 문제가 생깁니다. 이걸 폰노이만 병목이라고 부르는데, 컴퓨터는 이 문제를 캐시(cache)라는 빠른 임시 저장소와 지역성(locality)이라는 원리로 풀어내요. "캐시가 왜 빠른가"는 면접 단골 중의 단골이니, 다음 시간에 제대로 잡아봅시다!


과제

[기초] 진법 변환과 2의 보수 손으로 풀기

연필과 종이만 있으면 됩니다. 계산기 없이 직접 손으로 풀어보세요.

  1. 2진수 1011 0110을 10진수로 바꾸고, 16진수로도 바꿔보세요. (힌트: 16진수는 4비트씩 끊기)
  2. 10진수 100을 2진수와 16진수로 각각 바꿔보세요.
  3. 8비트 기준으로 -12를 2의 보수로 표현해보세요. (양수 12를 2진수로 → 비트 반전 → +1)
  4. 만든 -12+12를 더해서 결과가 0이 되는지(맨 앞 올림은 버림) 검산해보세요.

[응용] 부동소수점 오차와 UTF-8 바이트 수 직접 확인하기

직접 코드로 눈으로 확인하는 과제입니다. 평소 쓰는 언어 아무거나 좋아요.

  1. 0.1 + 0.2를 출력해보고, 0.3==로 비교하면 어떤 결과가 나오는지 확인하세요.
  2. 0.1 + 0.20.3의 차이가 아주 작은 값(예: 0.0000001)보다 작은지로 비교하면 어떻게 되는지 해보세요.
  3. 문자열 "A", "가", "😀"를 UTF-8로 인코딩했을 때 각각 몇 바이트인지 출력해보세요. (언어마다 인코딩·바이트 길이를 구하는 함수가 있어요.)
  4. 결과가 각각 왜 1·3·4바이트인지 오늘 배운 내용으로 설명해보세요.

[심화] "왜 하필 2진수인가"를 한 단계 더 파보기

조사하고 생각을 글로 정리하는 과제입니다.

  1. 컴퓨터가 2진수가 아니라 3진법(0, 1, 2)을 썼다면 어떤 장단점이 있었을지 조사해보세요. (실제로 3진법 컴퓨터가 있었습니다. "Setun"으로 검색해보세요.)
  2. 그럼에도 2진법이 표준이 된 이유를, 오늘 배운 "전기 신호의 확실성" 관점에서 한 문단으로 정리해보세요.

생각해볼 주제

1. 컴퓨터는 정말 0과 1밖에 모를까?

우리는 "컴퓨터는 0과 1만 안다"고 배웠습니다. 그런데 정말 물리적으로 0과 1 두 개만 존재할까요? 사실 그 0과 1도 "전압이 일정 기준보다 높으면 1, 낮으면 0"으로 약속한 것일 뿐, 실제 회로엔 연속적인 전압이 흐릅니다. 만약 전압을 0·1·2·3 네 단계로 나눠 쓰면 한 번에 더 많은 정보를 담을 수 있을 텐데, 왜 굳이 두 단계로만 딱 잘라 쓸까요? "노이즈(잡음)에 대한 강함"이라는 키워드로 생각해보세요.

2. 은행 잔고를 실수(float)로 저장하면 안 되는 이유

쇼핑몰 장바구니에 1,900원짜리 물건 3개를 담으면 5,700원이어야 합니다. 그런데 가격을 부동소수점(float)으로 저장하고 할인·세금 계산을 반복하면, 어느 순간 5,699.99999...원이나 5,700.00001원 같은 값이 나올 수 있어요. 1원도 안 되는 오차지만, 이게 수백만 건의 거래에 쌓이면 어떻게 될까요? 실무에서 돈을 다룰 때 float/double 대신 무엇을 써야 하는지, 그리고 "정수로 환산해서(원이나 더 작은 단위로) 저장한다"는 전략이 왜 안전한지 정리해보세요.

3. 이모지 하나가 왜 여러 바이트를 차지할까?

친구에게 😀를 보내면, 그 작은 그림 하나가 컴퓨터 안에서는 4바이트(32비트)를 차지합니다. 알파벳 'A'가 1바이트인 것에 비하면 4배죠. 더 나아가 어떤 이모지(예: 가족 이모지 👨‍👩‍👧‍👦)는 여러 이모지가 보이지 않는 연결 문자로 묶여 훨씬 더 많은 바이트를 차지하기도 합니다. 왜 이런 구조가 됐는지, 그리고 이게 "문자열 길이"를 셀 때 어떤 혼란을 일으킬지(눈에는 글자 하나인데 길이가 7로 나오는 상황) 생각해보세요.

✅ 예시 답안정답 보기

과제 예시답안

🎯 [과제 1 예시답안] 진법 변환과 2의 보수 손으로 풀기

채점 포인트

항목 배점 기준
2진수 → 10진수·16진수 변환 30% 1011 0110을 자릿값 합으로 풀고, 4비트씩 끊어 16진수로 바꿨는가
10진수 → 2진수·16진수 변환 25% 100을 2의 거듭제곱 합으로 분해했는가
2의 보수로 음수 표현 30% 비트 반전 후 +1 절차를 정확히 따랐는가
검산 15% -12 + 12가 0이 됨을 올림 버림으로 확인했는가

풀이

1. 1011 0110 → 10진수·16진수

자릿값을 적고 켜진(1) 자리만 더합니다.

텍스트
   1   0   1   1   0   1   1   0
  128  64  32  16   8   4   2   1
  128 + 0 +32 +16 + 0 + 4 + 2 + 0  =  182   (10진수)

16진수는 4비트씩 끊어서 바꿉니다.

텍스트
   1011  0110
    B     6        0xB6

(1011 = 11 = B, 0110 = 6) 검산하면 0xB6 = 11 × 16 + 6 = 182. 10진수 변환과 일치합니다.

2. 100 → 2진수·16진수

100에서 가장 큰 2의 거듭제곱부터 빼나갑니다. 64 + 32 + 4 = 100.

텍스트
   100  =  64 + 32 + 4  =  0110 0100   (2진수)
   0110 0100    6 4    0x64          (16진수)

3. -12를 8비트 2의 보수로

텍스트
   12  =  0000 1100      ① 양수 12
          1111 0011      ② 비트 반전
        +         1      ③ +1
        ──────────────
          1111 0100   =  -12

4. 검산 — -12 + 12 = 0?

텍스트
     0000 1100   ( 12)
   + 1111 0100   (-12)
   ─────────────
   1 0000 0000     맨 앞 올림 버림    0000 0000 = 0

💡 튜터의 포인트

손으로 직접 풀어보는 게 핵심이에요. 특히 2의 보수는 "비트 반전 → +1" 두 단계를 기계적으로 외우지 말고, 검산까지 해서 진짜 0이 되는 걸 눈으로 확인하면 원리가 몸에 남습니다. 16진수 변환은 "4비트 = 1자리" 규칙만 잡으면 2진수가 아무리 길어도 겁나지 않아요.


🎯 [과제 2 예시답안] 부동소수점 오차와 UTF-8 바이트 수 직접 확인하기

채점 포인트

항목 배점 기준
0.1 + 0.2 == 0.3 결과 확인 25% false가 나오는 것을 직접 확인했는가
오차범위 비교 25% epsilon보다 작은지로 비교해 true가 나옴을 확인했는가
UTF-8 바이트 수 출력 25% A·가·😀가 각각 1·3·4바이트임을 확인했는가
원리 설명 25% 왜 그런 결과인지 오늘 배운 내용으로 설명했는가

풀이

언어는 무엇이든 좋습니다. 결과만 보면 됩니다.

1~2. 부동소수점 비교

텍스트
   0.1 + 0.2               0.30000000000000004
   (0.1 + 0.2) == 0.3      false   (오차 때문에 다른 값)

   |(0.1 + 0.2) - 0.3| < 0.0000001     true   (오차범위 안이면 같다고 본다)

직접 비교(==)는 false, 오차범위 비교는 true. 실수를 다룰 땐 후자가 정답입니다.

3~4. UTF-8 바이트 수

텍스트
   "A"     1바이트   (ASCII 범위, U+0041)
   "가"    3바이트   (한글, U+AC00)
   "😀"    4바이트   (이모지, U+1F600)

왜 1·3·4바이트일까요? UTF-8은 가변 길이 인코딩이라, 코드 포인트 번호가 작을수록 적은 바이트를 씁니다. 영어(ASCII)는 번호가 작아 1바이트, 한글은 중간 영역이라 3바이트, 이모지는 아주 큰 번호라 4바이트가 필요해요.

💡 튜터의 포인트

직접 출력해보면 "아, 진짜네!" 하는 순간이 옵니다. 특히 0.1 + 0.2 == 0.3이 false인 걸 처음 보면 충격이죠. 이걸 한 번 겪어두면, 나중에 실무에서 "왜 금액이 1원 안 맞지?" 하는 버그를 만났을 때 바로 부동소수점을 의심할 수 있어요. UTF-8 바이트 수는 한글 서비스를 만들 때 "DB 컬럼 길이를 글자 수가 아니라 바이트로 잡으면 한글이 잘린다" 같은 실무 함정과 곧장 이어집니다.


🎯 [과제 3 예시답안] "왜 하필 2진수인가"를 한 단계 더 파보기

채점 포인트

항목 배점 기준
3진법 장단점 조사 40% 3진법의 장점(정보 밀도)과 단점(회로 복잡성)을 조사했는가
2진법이 표준인 이유 정리 40% "전기 신호의 확실성" 관점으로 설명했는가
자기 언어로 정리 20% 베껴 쓰지 않고 자기 문장으로 정리했는가

풀이 예시

3진법(0, 1, 2)의 장단점

  • 장점: 한 자리에 3가지를 담으니 같은 자릿수로 더 많은 수를 표현합니다. 이론적으로 정보 밀도가 높아 더 적은 자리로 같은 정보를 담을 수 있어요. 실제로 1958년 소련에서 "Setun"이라는 3진법 컴퓨터가 만들어지기도 했습니다.
  • 단점: 전기 회로로 "세 가지 상태"를 안정적으로 구분하기가 어렵습니다. 0과 1(꺼짐/켜짐)은 분명하지만, 중간 단계(예: 절반 전압)는 노이즈에 흔들려 0인지 2인지 헷갈리기 쉬워요.

2진법이 표준이 된 이유

컴퓨터는 전기로 동작하고, 전기 신호는 "흐른다/안 흐른다" 두 상태가 가장 확실합니다. 상태를 두 개로만 나누면 웬만한 노이즈가 끼어도 0과 1을 헷갈리지 않아요. 반면 상태를 셋·넷으로 늘릴수록 각 단계 사이 간격이 좁아져 오류가 급증합니다. 정보 밀도를 조금 포기하더라도 신호의 확실성과 회로의 단순함을 택한 것이 2진법이 표준이 된 이유입니다.

💡 튜터의 포인트

이 과제의 목적은 "2진수가 당연하다"를 넘어 "왜 다른 선택지를 두고 2진수가 이겼나"를 따져보는 거예요. 기술 선택에는 늘 트레이드오프가 있다는 감각, 이게 면접에서 "왜?"를 세 번 받아도 버티는 힘이 됩니다.


생각해볼 주제 예시답안

🤔 [생각해볼 주제 1 예시답안] 컴퓨터는 정말 0과 1밖에 모를까?

[문제 상황 요약]

"컴퓨터는 0과 1만 안다"는 말은 사실 약속의 결과입니다. 실제 회로엔 연속적인 전압이 흐르는데, 왜 굳이 두 단계로만 잘라 쓸까요? 네 단계로 나누면 정보를 더 담을 수 있을 텐데요.

[튜터의 가이드 및 해설]

핵심은 노이즈(잡음)에 대한 강함입니다.

전선에 흐르는 전압은 깔끔한 0V·5V가 아니라 늘 미세하게 흔들립니다. 주변 전자기파, 열, 전압 변동 같은 잡음이 끼거든요. 그래서 "정확히 5V"가 아니라 "대략 5V 근처"로 신호가 도착합니다.

  • 2단계(0과 1): "2.5V보다 높으면 1, 낮으면 0"으로 약속하면, 신호가 1V쯤 흔들려도 0과 1을 헷갈릴 일이 거의 없습니다. 두 상태 사이 간격이 넓으니까요.
  • 4단계(0·1·2·3): 0V·1.6V·3.3V·5V로 나눈다면, 각 단계 사이 간격이 약 1.6V로 좁아집니다. 신호가 조금만 흔들려도 1을 2로 잘못 읽는 오류가 폭증해요.

즉 단계를 늘리면 정보 밀도는 올라가지만 오류에 약해집니다. 컴퓨터는 무엇보다 정확성이 중요하기 때문에, 정보 밀도를 양보하고 가장 튼튼한 2단계를 택한 거예요. (참고로 플래시 메모리(SSD)는 저장 밀도를 높이려고 실제로 한 셀에 4·8단계를 욱여넣기도 하는데, 그만큼 오류 정정 회로가 복잡하고 수명이 짧아지는 대가를 치릅니다.)

🎯 면접관을 홀리는 핵심 멘트

"컴퓨터가 2진법을 쓰는 건 물리적으로 0과 1만 존재해서가 아니라, 노이즈에 가장 강한 선택이기 때문입니다. 전기 신호는 늘 흔들리는데, 상태를 두 개로만 나누면 그 사이 간격이 넓어서 웬만한 잡음에도 0과 1을 안정적으로 구분합니다. 단계를 늘리면 정보 밀도는 오르지만 오류율이 급증하죠. 컴퓨터는 정확성이 최우선이라 정보 밀도를 양보하고 신호의 확실성을 택한 겁니다."


🤔 [생각해볼 주제 2 예시답안] 은행 잔고를 실수(float)로 저장하면 안 되는 이유

[문제 상황 요약]

1,900원짜리 3개는 5,700원이어야 하는데, 부동소수점으로 할인·세금 계산을 반복하면 5,699.99999...원 같은 값이 나올 수 있습니다. 1원도 안 되는 오차지만, 수백만 건이 쌓이면 어떻게 될까요?

[튜터의 가이드 및 해설]

이건 Step 5에서 본 부동소수점 오차가 이라는 가장 민감한 영역에서 터지는 경우예요.

문제의 본질

부동소수점은 0.1조차 정확히 저장하지 못합니다. 그래서 금액 계산을 반복할 때마다 미세한 오차가 누적되고, 어느 순간 "총합이 1원 안 맞는" 상황이 생겨요. 한 건에선 무시할 수준이지만, 거래 수백만 건·이자 계산 수억 번이 쌓이면 회계가 안 맞는 사고로 번집니다.

해결책 1 — 십진 전용 타입

BigDecimal(Java), Decimal(파이썬·C#) 같은 타입은 10진수를 오차 없이 다룹니다. 내부적으로 "숫자와 소수점 위치"를 따로 저장해서 0.1을 진짜 0.1로 보관해요. 다만 부동소수점보다 느리고 메모리를 더 씁니다.

해결책 2 — 정수로 환산

더 간단하고 빠른 방법은 가장 작은 단위의 정수로 저장하는 거예요. 1,900원을 그냥 정수 1900으로 다루면 오차가 원천적으로 안 생깁니다. 화면에 보여줄 때만 소수점·콤마를 붙이고요. 많은 결제 시스템이 이 방식을 씁니다.

🎯 면접관을 홀리는 핵심 멘트

"금액에 float/double을 쓰면 안 되는 이유는 부동소수점이 0.1조차 정확히 표현하지 못해 오차가 누적되기 때문입니다. 한 건에선 미미해도 거래가 쌓이면 회계가 어긋나는 사고가 됩니다. 그래서 정확성이 필요한 금액은 BigDecimal 같은 십진 전용 타입을 쓰거나, 더 간단하게는 가장 작은 단위의 정수로 환산해 저장합니다. 정수 연산은 오차가 없으니까요. 핵심은 '돈은 부동소수점으로 다루지 않는다'는 원칙입니다."


🤔 [생각해볼 주제 3 예시답안] 이모지 하나가 왜 여러 바이트를 차지할까?

[문제 상황 요약]

😀 하나가 4바이트, 가족 이모지 👨‍👩‍👧‍👦는 그보다 훨씬 많은 바이트를 차지합니다. 'A'가 1바이트인 것과 대비되죠. 게다가 이게 "문자열 길이"를 셀 때 혼란을 일으킵니다.

[튜터의 가이드 및 해설]

Step 6에서 본 UTF-8의 가변 길이와 유니코드 구조가 합쳐진 이야기예요.

왜 이모지는 바이트가 클까

UTF-8은 코드 포인트 번호가 클수록 더 많은 바이트를 씁니다. 알파벳은 작은 번호(U+0041)라 1바이트지만, 이모지는 아주 큰 번호(U+1F600 이상)라 4바이트가 필요해요. 이모지가 유니코드에 늦게, 즉 번호가 높은 영역에 추가됐기 때문입니다.

가족 이모지의 정체

👨‍👩‍👧‍👦는 사실 한 글자가 아니에요. 남자·여자·여아·남아 네 개의 이모지를 보이지 않는 연결 문자(ZWJ, Zero Width Joiner)로 묶은 겁니다. 그래서 화면엔 하나로 보여도 내부적으로는 여러 코드 포인트가 줄줄이 이어져 있어 바이트 수가 훨씬 큽니다.

"문자열 길이"의 혼란

여기서 실무 함정이 생깁니다. 많은 언어에서 👨‍👩‍👧‍👦의 길이를 재면 1이 아니라 7 같은 엉뚱한 숫자가 나와요. "사람 눈에 보이는 글자 1개"와 "코드 포인트 개수"와 "바이트 수"가 전부 다르기 때문이에요. 그래서 글자 수 제한(예: "한 줄에 20자")을 단순히 길이로 구현하면 이모지 사용자에게 엉뚱하게 동작합니다. 정확히 다루려면 "사람이 인식하는 글자 단위"(grapheme cluster)로 세야 해요.

🎯 면접관을 홀리는 핵심 멘트

"이모지가 여러 바이트인 이유는 UTF-8이 가변 길이라 코드 포인트 번호가 큰 문자일수록 많은 바이트를 쓰기 때문입니다. 이모지는 유니코드의 아주 높은 번호 영역이라 4바이트를 차지하고, 가족 이모지처럼 여러 문자를 연결 문자(ZWJ)로 묶은 경우는 더 커집니다. 실무에서 중요한 건 '눈에 보이는 글자 수'와 '코드 포인트 수'와 '바이트 수'가 모두 다르다는 점이에요. 문자열 길이를 셀 때 이걸 구분하지 않으면 이모지나 한글에서 버그가 납니다."

전체 목록 CS 기초지식