새 분야를 조사할 일이 생겨 단위부터 봤다.
1 BTC
0.01 BTC
0.001 BTC
0.000001 BTC
0.00000001 BTC
최소 단위가 소수점 여덟 자리까지 있었다. DECIMAL 로 치면 소수부가 8 이다.
Table of contents
Open Table of contents
왜 이렇게 작나
우리가 쓰는 돈은 최소 단위가 1 원이고 소수점이 없다. INT 하나로 끝난다. 여덟 자리는 처음에 이해가 안 됐다.
읽어 보니 이 화폐는 총량이 정해져 있었다. 필요하면 더 찍는 방식이 아니라 상한이 있는 방식이다. 여기서 이유가 갈렸다.
총량이 고정이면 나누는 수밖에 없다
총량이 고정인데 쓰는 사람이 늘면 더 찍을 수가 없으므로 한 단위를 잘게 쪼개는 수밖에 없다. 값이 오르면 더 그렇다. 한 단위가 커피 한 잔 값일 때는 그대로 쓸 수 있지만 자동차 한 대 값이 되면 작은 거래를 못 한다.
자릿수를 나중에 늘리면 이미 기록된 값들과 안 맞는다. 그래서 처음에 넉넉히 잡아 둔 것으로 보인다. 나중에 바꿀 수 없는 것을 처음에 정해 둔 셈이다.
검증 — 저장 방식을 따져 봤다
여기서 프로그램 쪽이 걱정됐다. 소수점 여덟 자리를 실수형에 담으면 근사값이라 계산할 때마다 오차가 쌓인다. IEEE 754 는 2진 분수로 값을 만드는데 0.1 이나 0.01 은 2진으로 유한하게 안 떨어진다. 돈은 오차가 나면 안 된다. MySQL 5.6 매뉴얼도 DECIMAL 을 돈처럼 정확한 정밀도를 지켜야 하는 값에 쓰는 정확 수치형으로 설명하고 BIGINT 의 범위를 -9,223,372,036,854,775,808 부터 9,223,372,036,854,775,807 까지로 적는다.
최소 단위를 1 로 세는 방법이 떠올랐다.
0.00000001 을 1 로 센다
1 BTC = 100,000,000
정수로 세고 표시할 때만 나누면 오차가 안 생긴다. 대신 수가 커져서 1 단위가 1억이고 1,000 단위면 1,000억이다.
총량이 수천만 단위라면 곱해서 수천조가 된다. 32비트 부호 있는 정수의 최대는 2,147,483,647 로 약 21억이니 턱없이 모자란다. 64비트는 약 922경까지라 여유가 있다. MySQL 이면 INT 가 아니라 BIGINT 다.
실수형으로 담는다면 크기 쪽에도 한계가 하나 더 있다. IEEE 754 배정밀도가 정수를 정확히 표현하는 범위는 2의 53승까지이고 그 수가 약 900조다. 수천조가 그 아래이긴 하지만 여유가 몇 배 남짓이다. 크기보다 앞서 걸리는 것은 소수 표현 쪽이다.
이 계산을 하고 나서 보인 것이 있다. 최소 단위를 얼마로 할지와 총량이 얼마인지가 정해지면 저장할 자료형이 따라 나온다. BIGINT 로 세는 쪽과 DECIMAL(16,8) 로 담는 쪽이 갈리는 지점도 거기다. 거꾸로 자료형을 먼저 정하고 그 범위 안에서 총량과 최소 단위를 정할 수도 있다. 나라면 세는 쪽을 골랐을 것이다. 이유는 곱셈과 덧셈이 정수 연산으로 끝나 반올림 규칙을 따로 정할 일이 없다는 점이다. 대신 표시할 때마다 나누는 코드가 붙는 것을 감수하고 가는 것이다.
단위 이름
각 자릿수에 이름이 붙어 있었다.
0.01 센티
0.001 밀리
0.000001 마이크로
국제 단위계 접두어를 그대로 빌린 것이었다. milli 와 micro 는 길이나 무게에서 이미 쓰는 것이라 새로 외울 것이 없다. 새 이름을 만들면 그만큼 외워야 하는데 익숙한 규칙을 가져오면 그 비용이 없어진다.
가장 작은 단위만 이름이 다르다. 접두어 규칙에는 여덟 자리에 맞는 이름이 없고(nano 는 아홉 자리다) 만든 사람 이름에서 딴 별칭이 붙어 있다. 가장 작은 단위라 특별하게 본 것 같은데 규칙에서 벗어나니 이것만 따로 외워야 한다. 일관성과 의미 중 하나를 고른 셈이다.
조사를 하면서 단위를 보는 눈이 좀 달라졌다. 단위는 그냥 정하는 숫자라고 생각했는데 총량과 값의 변화와 저장 방식이 다 얽혀 있었다.
정리
- 최소 단위가 소수점 여덟 자리까지 있다 —
DECIMAL로 치면 소수부가 8 이다 - 총량이 고정이라 더 못 만들고 나누는 수밖에 없다
- 값이 오르면 작은 거래를 하려고 잘게 나눠야 한다
- 자릿수를 나중에 늘리면 이미 기록된 값들과 안 맞는다
- 돈은 오차가 나면 안 되니 정수로 세고 표시할 때만 나눈다
- IEEE 754 는 0.1 이나 0.01 을 2진으로 유한하게 못 담는다
- 그러면 수가 커져서
INT가 아니라BIGINT가 필요하다 - 32비트는 약 21억, 64비트는 약 922경까지다
milli와micro같은 익숙한 접두어를 빌리면 새로 안 외워도 된다- 하나만 예외인데 일관성과 의미 중 하나를 고른 것으로 보인다