3강 / 20강

숫자와 글자 — 돈 계산이 틀리는 이유

2의 보수 · 오버플로 · 실수 오차 · 한글 인코딩

숫자와 글자 — 돈 계산이 틀리는 이유
같은 비트라도 어떻게 읽기로 약속했느냐에 따라 -1도 되고 65535도 됩니다.

메모리에 11111111 11111111 이 들어 있습니다. 이건 얼마일까요?

  • 부호 없는 수로 읽으면 → 65535
  • 부호 있는 수로 읽으면 → -1
  • 글자로 읽으면 → 깨진 문자

비트 자체에는 뜻이 없습니다. 어떻게 읽기로 약속했는지가 전부예요. 이 약속을 헷갈리면 쇼핑몰에서 주문 금액이 음수가 되는 사고가 납니다.

음수를 만드는 법 — 2의 보수

비트에는 마이너스 기호가 없습니다. 그래서 이렇게 약속했어요.

🔄
① 뒤집는다
모든 비트를 반대로
➕
② 1을 더한다
그게 음수다

왜 이렇게 이상하게 만들었을까요? 뺄셈기를 따로 만들 필요가 없어지기 때문입니다. 5 - 3 을 5 + (-3) 으로 계산해도 덧셈기 하나로 답이 맞아떨어져요. 회로가 절반으로 줄어듭니다.

뺄셈이 덧셈으로 둔갑하는 마술.
Python 브라우저에서 실행
수 표현 실험실 — 같은 비트를 여러 방식으로 읽어 보고, 오버플로를 직접 일으켜 보세요.
불러오는 중…

미니 CPU로 오버플로를 직접 일으켜 봅시다

아래는 이 강의에서 쓰는 미니 CPU의 어셈블리입니다. 16비트 레지스터라서 32767을 넘으면 음수로 돌아버려요. ▶ 실행을 눌러 보세요.

합계가 33,000원이 되어야 하는데 …
미니 CPU 브라우저에서 실행

결과가 -32536 이 나왔을 겁니다. 33000은 16비트 부호 있는 수의 최댓값(32767)을 넘거든요. CPU는 V(오버플로) 플래그를 세워서 "넘쳤다"고 알려 주지만, 프로그램이 그 플래그를 확인하지 않으면 그냥 음수인 채로 넘어갑니다.

그래서 실무에서는 돈은 넉넉한 정수 타입(64비트)이나 고정소수점으로 다룹니다.

실수는 왜 항상 조금 틀릴까

파이썬에서 0.1 + 0.2 를 해 보면 0.30000000000000004 가 나옵니다. 버그가 아니라 2진법으로는 0.1을 정확히 적을 수 없기 때문입니다. 10진법으로 1/3을 0.3333… 이라고 영원히 적어야 하는 것과 같아요.

돈을 float 으로 다루면 안 되는 이유.
Python 브라우저에서 실행

한글은 몇 바이트인가

영어 한 글자는 1바이트(ASCII)입니다. 그런데 한글은요?

지금 표준인 UTF-8에서 한글 한 글자는 3바이트입니다. 그래서 DB에 VARCHAR(10)이라고 잡아 놓고 "열 글자 들어가겠지" 했다가 세 글자만 들어가는 사고가 나요.

한글 한 글자 = 3바이트. 자르는 위치를 잘못 잡으면 깨집니다.
Python 브라우저에서 실행
가상 서버에서 한글의 바이트를 벗겨 봅니다.
bash 브라우저에서 실행
🤔 확인 문제
8비트 부호 있는 정수에 저장된 재고가 -128 입니다. 여기서 1을 더 빼면?
🤔 확인 문제
쇼핑몰 DB에 상품 설명을 VARCHAR(30)으로 잡았는데 한글 12자를 넣으니 거절당했습니다. 가장 그럴듯한 원인은?