Lemma
수학, 거꾸로
도입 · 지수가 몇이냐

2를 몇 번 곱해야 1,024가 될까?

답은 10. 그 10이 log2(1,024)\log₂(1,024)다. 로그는 거듭제곱의 역함수 — 결과에서 지수를 꺼낸다. 자연에 등장하는 큰 수는 거의 다 지수에서 자란다. 세포는 두 배가 되고, 이자는 복리로 쌓이고, 별빛은 1/r21/r²로 흐려지고, 소리는 열두 자릿수에 걸쳐 변한다. 우리가 보는 결과 (세포 1,024개, 100배로 불어난 돈, 진도 7.2)는 자연이 쓰는 매개변수가 아니다. 지수 (몇 번 두 배 됐나, 몇 년 굴렸나)가 매개변수다. 로그는 그 지수를 꺼내주는 함수다. 익숙한 특수한 경우가 이미 하나 있다 — log10(1,000,000)=6\log₁₀(1,000,000) = 6인 건 0이 6개여서다. 일상의 자릿수란 곧 10을 밑으로 한 지수. 자릿수를 다른 밑으로 일반화하면 로그가 된다. 그리고 지수는 밑이 곱해질 때 더해지므로, 로그는 곱셈을 덧셈으로 바꾼다: log(ab)=log(a)+log(b)\log(a·b) = \log(a) + \log(b). 이 페이지의 나머지는 모두 이 한 줄에서 따라 나온다.

로그 = 지수가 몇이냐. 나머지 — log(ab)=log(a)+log(b)\log(a·b) = \log(a) + \log(b), 계산자, 로그우도, 자릿수 추정 — 는 따름정리.

도구 사양
정의

거듭제곱의 역함수. log(ab)=log(a)+log(b)\log(a·b) = \log(a) + \log(b) — 곱이 합이 된다. 모듈에 식은 이 하나뿐.

적용

어떤 양이 지수에서 자라났을 때 — 복리, 반감기, 데시벨, 지진 규모, 시퀀스 확률. 자연이 쓰는 변수가 몇 번 곱했는가이고, 그 횟수를 결과에서 되찾고 싶을 때.

한계

인수가 0 이하면 실수 로그는 정의되지 않는다. 밑이 1이면 어떤 지수든 결과가 1이라 역함수가 무너진다. 가장 흔한 학생 실수는 합에 로그를 씌우는 것이다: log(a+b)log(a)+log(b)\log(a + b) ≠ \log(a) + \log(b). 항등식 아래엔 반드시 곱이 있어야 한다.

위젯 A — 두 배의 사다리
정방향 — 거듭제곱
2
4
지수
=
16
결과
역방향 — 로그
log
함수
(
16
결과
)
=
4
지수
세 슬라이더 — 밑 b, 지수 n, 결과 r — 은 모두 같은 식 bⁿ = r 위에 있다. n을 끌면 r이 자라거나 줄어든다. r을 끌면 가장 가까운 b의 거듭제곱으로 스냅되고, 답이 n으로 떨어진다 — 그게 곧 log_b(r). 오렌지(n) 와 검정(r) 이 함께 움직이는 것 자체가 로그가 결과에서 지수를 꺼낸다는 사실의 그림.
위젯 B — 두 자
log₁₀(a)0.30
log₁₀(b)0.48
log₁₀(a) + log₁₀(b)0.78
a · b6.00
선형02004006008001000log₁₀1101001000a = 2.00b = 3.00a·b = 6.00a·b
a = 2, b = 3으로 드래그. 마커가 6에 떨어진다 — 곱한 적은 한 번도 없다. 두 로그 거리를 더했을 뿐. b5로 드래그하면 마커가 10으로 점프. 같은 트릭.
흐름
1

모든 일을 하는 항등식

로그를 정의하는 줄은 단 하나다: log(ab)=log(a)+log(b)\log(a·b) = \log(a) + \log(b). 밑은 뭐든 좋다. 규칙은 같다. (밑은 분야가 정해준다: log\log는 공학·고등학교에서는 , ML·통계에서는 , 알고리즘에서는 log2\log₂ — 첨자가 없으면 분야로 읽는다.) 나머지 성질은 모두 이 한 줄에서 따라 나온다. log(a/b)=log(a)log(b)\log(a/b) = \log(a) − \log(b): 규칙에서 b를 1/b로 바꾸면 끝. log(an)=nlog(a)\log(aⁿ) = n·\log(a): 규칙을 aaaa · a · … · a에 n번 적용. log(1)=0\log(1) = 0: log(1a)=log(1)+log(a)\log(1·a) = \log(1) + \log(a)에서 곧장. 네 번째 규칙은 없다 — 곱셈을 묶는 네 번째 방법이 없기 때문이다. 실용적으로 말하면: 는 어떤 수가 밑을 몇 번 곱해 만들어졌는지를 알려준다. log10(1000)=3\log₁₀(1000) = 3인 건 1000이 10을 세 번 곱한 수이기 때문. 곱한 횟수를 센다. 그게 전부다.

import math

# every log law from one identity:
math.log10(2 * 50)              # ≈ math.log10(2) + math.log10(50)
math.log10(2 ** 10)             # ≈ 10 * math.log10(2)
math.log10(1)                   # 0.0
2

같은 트릭, 다섯 곳

지수에서 자라는 양은 여기저기 흩어져 있다 — 시간에 따라 자라는 것 (, 탄소 연대 측정), 감각이 누르는 압축 (데시벨), 거대한 스케일을 재는 단위 (지진), 정보를 세는 단위 (비트). 매번 같은 트릭이다: 식을 세우고, 양변에 로그를 씌우고, 지수를 꺼낸다. 손으로 풀어보자.

  • 복리. 100만원을 연 7%로 굴리면 두 배가 되는 데 몇 년? 1.07t=21.07ᵗ = 2t=log(2)/log(1.07)0.301/0.029410.24t = \log(2) / \log(1.07) ≈ 0.301 / 0.0294 ≈ 10.24 \text{년}. (72/710.372 / 7 ≈ 10.3)은 이 식을 작은 r에서 어림한 것.
  • 탄소-14 연대 측정. 탄소-14는 생물이 죽으면 반감기 5,730년으로 줄어든다. 25%만 남았다면: (1/2)(t/5730)=0.25=(1/2)2(1/2)^(t/5730) = 0.25 = (1/2)²t=11,460t = 11{,}460 \text{년}. 33%, 17%처럼 어중간한 비율은 로그 식 한 줄이 아니면 닫히지 않는다.
  • 데시벨. dB=10log10(P/P0)dB = 10·\log₁₀(P/P₀). 일상 대화 60 dB, 록 콘서트 110 dB → 음향 강도는 105=10만 배10^5 = \text{10만 배} 차이. 귀에는 그렇게 들리지 않는다. 귀가 강도를 로그 스케일로 듣기 때문 — 데시벨은 그 압축을 그대로 단위로 옮긴 것이다.
  • 지진 규모. E=E010(1.5M)E = E₀·10^(1.5·M). 2011 도호쿠 (M 9.0) vs 평범한 큰 지진 (M 7.0): E9/E7=101.5×2=103=1,000E_9 / E_7 = 10^{1.5×2} = 10^3 = 1{,}000\text{배}. 규모 2 차이가 에너지 1,000배. 자연 지진 에너지는 19자릿수에 걸쳐 있어, 리히터의 로그 압축이 없으면 비교 자체가 안 된다.
  • 비트와 이진 탐색. 1,024쪽 사전을 매번 반으로 자르면 log2(1024)=10\log₂(1024) = 10번이면 단어에 닿는다. 32비트 정수는 23243억2^{32} ≈ \text{43억} 가지를 담고, 거꾸로 N개를 식별하려면 log2(N)\log₂(N) 비트가 필요하다. 카드 한 벌을 섞으면 log2(\log_2()226 비트) ≈ 226 \text{ 비트}의 정보 — 예/아니오 질문 226개면 그 한 번의 셔플이 정확히 특정된다.

다섯 문제, 모양은 하나: 자연이 만든 식은 지수꼴, 양변에 로그, 지수가 답으로 떨어진다. § 1의 항등식 — 곱셈을 덧셈으로 — 이 매번 그 일을 한다.

3

네이피어와 계산자 (×→+ 의 화신)

1614년, 존 네이피어가 첫 로그 표를 펴냈다. 일식을 예측하려고 9자리 수를 손으로 곱하다 속이 타들어 가던 천문학자들의 시대였다. 표를 펴서 log(a)\log(a)log(b)\log(b)찾고, 둘을 더하고, 그 합이 로그값인 수를 다시 찾기만 하면 — 곱셈 한 번 없이 aba·b가 나왔다. 300년 뒤, 모든 엔지니어가 를 들고 다녔다. 로그 눈금 두 개가 서로 미끄러지는 나무 자. 한쪽의 2를 다른 쪽의 3에 맞추면 물리적으로 log(2)+log(3)\log(2) + \log(3)이 수행됐고, 만나는 자리에 6이 찍혔다. 계산자는 § 1의 항등식을 깎아 만든 도구다. 아폴로는 이걸로 달에 갔다.

4

언더플로우 — 그리고 로그 공간이 모델을 살리는 이유

는 약 103810⁻³⁸까지만 표현한다. 확률 0.10.1을 마흔 번 곱하면 그 선 아래로 떨어지고 — 결과는 조용히 0으로 반올림된다. 예외도, 경고도 없다. 거기에 매달려 있던 모든 가 함께 죽는다. 수치해석의 흥밋거리가 아니다. 모든 딥러닝 라이브러리가 손실을 이 아니라 으로 보고하는 이유다. 해법은 § 1의 항등식을 기계적으로 적용하는 것: 곱이 만들어지기 직전에 로그를 씌운다. log(p1p2pn)=Σlog(pi)\log(p₁·p₂·…·pₙ) = Σ \log(pᵢ). 각각의 log(pi)\log(pᵢ)는 다루기 편한 음수, 그 합은 다루기 편한 더 큰 음수. 가 닿을 수 없는 자리다. 가 하는 일이고,

가 만들어진 이유다. 로그 공간에 머물면 곱은 합이 되고, float는 더는 거짓말을 하지 않는다.

import numpy as np

# Naive: multiply 40 probabilities. Underflows in float32.
p = np.float32(0.1)
np.prod([p] * 40)               # → 0.0  (silent death)

# Log-space: add 40 log-probabilities. Survives.
np.sum(np.log([p] * 40))        # → -92.10  (well-defined)
5

이게 어디에 나타나나 — 같은 항등식, 두 필러

로그는 덧셈의 질문에 곱셈이 답하게 해주는 도구다. 무언가가 곱으로 쌓이는 모든 분야 — 그런 분야가 많다 — 는 결국 “몇 번?”, “얼마나 큰가?”, “얼마나 확신하나?”를 덧셈의 모양으로 묻게 된다. 그 다리가 로그다.

finance : 이율은 곱으로 합쳐진다 — 로그가 그것을 더하기로 만든다
        (목표까지 햇수, CAGR, 연속 복리).
ml      : 독립적인 가능도는 곱으로 합쳐진다 — 로그가 그것을 더하기로
        만들고, *음의* 로그가 그것을 손실로 만든다.

이 모듈을 실제로 쓰는 다섯 곳이 있다. 모두 § 1의 한 항등식에 기댄다 —

  • 비트코인 피자는 복리 성장의 역연산 — F=P(1+r)tF = P(1+r)^t는 로그를 씌우지 않으면 t에 대해 풀 수 없다. t=log(F/P)/log(1+r)t = \log(F/P) / \log(1+r). CAGR은 같은 항등식을 r에 대해 푼 것. 세 미지수, 한 식, 로그 모양의 답 셋.
  • 현재가치는 이산 복리 (1+r/n)(nt)(1 + r/n)^(n·t)에서 연속 형식 e(rt)e^(rt)로 건너가는 다리를 놓는다 — 이산 식에 로그를 씌우면 극한에서 rtr·t로 정리된다. 연속 복리는 별개의 연산이 아니라, 이산 연산을 로그로 들여다본 것뿐.
  • 자신 있게 틀리기는 손실 logp정답−\log p_{\text{정답}}를 만든다. 훈련 예제 여러 개의 가능도는 서로 곱해진다 — 로그가 그 곱을 합으로 바꾸고, 음의 부호가 “더 자신만만한 오답일수록 더 큰 손실”로 만든다.
  • TF-IDF는 희귀성을 비트로 잰다 — idf(t)=log(N/df(t))idf(t) = \log(N / df(t)). 로그가 “세 배 더 드물다”를 “1 비트 더 놀라운”으로 바꿔준다. 비트로 잰 다른 양 (비밀번호 강도, 영문자 엔트로피) 과도 곧장 비교할 수 있다.
  • 모델 캘리브레이션은 검증 셋의 로그 손실을 최소화해 온도 T를 맞춘다. 로짓 함수 log(p/(1p))\log(p/(1−p))는 캘리브레이션 곡선을 애초에 선형으로 펴주는 기저 변환. 한 작업 흐름 안에서 로그가 두 가지 역할로 등장한다.

다섯 문제, 두 필러, 항등식은 하나 — × → + 의 치환. § 3 네이피어의 계산자와 똑같은 기계가 오늘은 log_softmax와 캘리브레이션 옵티마이저 안에서 돌고 있다.

log(a·b) = log(a) + log(b). 모듈 전체. 나머지 — 자릿수 규칙, , , $10⁹ × 2.89²⁰ 손계산 — 은 따름정리.

exercises · 손으로 풀기
1그래프 읽기

위젯에서 a = 4로 두자. a·b가 정확히 100에 떨어지게 하려면 b는? 계산하지 말고 로그 축에서 읽어라.

2손으로 계산 · 자릿수 규칙계산기 없이

계산기 없이, log10(2)0.301\log₁₀(2) ≈ 0.301만 사용해서 **log₁₀(2,000,000)**을 구하라.

3식 세우기 · 시퀀스 확률

50토큰 시퀀스를 평가한다. 각 토큰의 확률은 ~0.05. 코드가 계산해야 할 식과 피해야 할 식을 각각 써라. log(0.05)3.00\log(0.05) ≈ −3.00 사용.

4손으로 계산 · 냅킨 한 장에 스털링계산기 없이

: log10(n!)nlog10(n)nlog10(e)\log₁₀(n!) ≈ n·\log₁₀(n) − n·\log₁₀(e), log10(e)0.434\log₁₀(e) ≈ 0.434. log₁₀(100!) 추정, 그리고 100!의 자릿수는?

5그래프 읽기 · 같은 로그 거리 = 같은 비율

위젯에서, log(b) − log(a)의 거리가 log(1)부터 log(10)까지의 거리와 같도록 두 핸들을 두면, 위치와 상관없이 b/a는 항상 얼마인가?

6식 세우기 · logsumexp

두 확률 p, q가 있다. 단, logp\log plogq\log q만 안다 (p, q 자체는 언더플로우). log(p+q)\log(p + q)의 수치적으로 안정한 식을 유도하라. ( 트릭이다.)

7악마의 문제 · '그냥 곱하면 되잖아'

주니어가 말한다: “는 그냥 성능 최적화일 뿐이고, 수학적으로는 그냥 확률을 곱해도 된다. 걱정되면 float64 쓰면 되잖아.” float64float64 둘 다에 대해 통하는 반박을 한 단락으로 써라. 그리고 로그 공간을 가능하게 만드는 단 하나의 방정식을 적어라.

용어집 · 이 페이지에서 쓰임 · 14
common log·상용로그
밑이 10인 로그. 공학에서 그냥 log(x)라고 쓰면 보통 상용로그를 가리킨다.
natural logarithm (ln)·자연로그
밑이 e ≈ 2.71828 인 로그. ln(x) 또는 log_e(x) 로 표기.
logarithm·로그
지수의 역연산. log_b(x) 는 'b를 몇 제곱하면 x가 되는가'를 묻는다.
compound interest·복리
원금 + 이미 쌓인 이자에 대해 다시 이자를 계산하는 방식. 매 기간 덧셈이 아니라 곱셈으로 불어난다.
Rule of 72·72의 법칙
원금이 두 배가 되는 데 걸리는 시간 ≈ 72 / (이율 %). 연 8%면 약 9년.
⚠ 왜 72인가? ln(2) ≈ 0.693, 작은 r에 대해 ln(1+r) ≈ r. 따라서 t ≈ 0.693/r. 72는 약수가 많고 근사 오차도 적당히 흡수해서 머리로 굴리기 편하다.
factorial·계승
`n!` 은 `1 × 2 × 3 × … × n`. 줄세우는 가짓수 — n개를 한 줄로 늘어놓는 방법의 수다. `5! = 120`. `52!` (카드 한 벌의 모든 셔플 순서) 는 68자리 수. 어떤 지수 `aⁿ` 보다도 빠르게 자란다. 그래서 `log(n!)` 과 스털링 근사가 따로 필요하다.
slide rule·계산자
두 개의 로그 눈금이 서로 미끄러지는 기계식 아날로그 계산기 (~1620년부터 ~1972년까지). 숫자를 맞추면 로그 거리가 물리적으로 더해져 곱셈이 됐다. 아폴로의 궤도도 이걸로 검산했다. 휴대용 전자 계산기가 등장하면서 순식간에 밀려났다.
float32·float32
32비트 IEEE-754 부동소수점 형식. 약 10진수 7자리 정밀도, 약 1e-38 에서 3.4e38 까지의 크기 범위. 범위를 벗어나는 수는 0 (언더플로우) 또는 무한대 (오버플로우) 로 반올림된다.
⚠ float64와는 다르다. float32는 ~1e-38 아래로 언더플로우, ~3.4e38 위로 오버플로우. ML 프레임워크가 float32를 기본으로 쓰는 건 GPU 메모리 대역폭이 병목이기 때문이다.
gradient·그래디언트
함수의 여러 방향 기울기를 한 번에 모은 것. 함수 f(x, y, z, ...) 에 대해 그래디언트는 편미분의 벡터 — 가장 가파른 상승 방향을 가리킨다. 머신러닝에서 이 벡터는 손실을 줄이려면 파라미터를 어느 쪽으로 옮겨야 하는지 옵티마이저에게 알려준다.
⚠ ML에서: 모든 파라미터에 대한 손실의 편미분 벡터. 최적화는 그래디언트의 반대 방향으로 한 걸음씩 이동한다 ("경사하강"). 그래디언트 계산에 들어가는 값이 언더플로우로 0이 되면 사슬 전체가 끊긴다 — 그래서 로그 공간이 중요하다.
underflow·언더플로우
표현하려는 수가 float 형식의 표현 가능 범위보다 너무 작아서 하드웨어가 0으로 반올림하는 현상. float32는 ~1e-38, float64는 ~1e-308 아래에서 발생.
⚠ 오버플로우와는 다르다. 언더플로우는 조용히 0으로 반올림된다 — 예외도 경고도 없다. 그 값에 닿은 그래디언트는 그대로 죽는다.
log-likelihood·로그우도
확률 (또는 확률들의 곱) 의 로그. 작은 확률들의 곱은 float에서 언더플로우하지만, 로그의 합은 깔끔하게 살아남기 때문에 그 형태로 다룬다.
⚠ (0,1) 사이 확률에 대해서는 항상 음수. 클수록 (덜 음수일수록) 좋다. '음의 로그우도(NLL)' 는 부호를 뒤집어 손실 함수로 최소화하기 위한 형태.
log_softmax·log_softmax
softmax 확률을 직접 만들지 않고 log(softmax(x)) 를 계산하는 수치적으로 안정한 함수. softmax 는 점수 벡터를 확률로 바꾸지만, 그 결과에 그대로 로그를 씌우면 작은 항이 언더플로우한다. log_softmax 는 logsumexp 트릭으로 두 단계를 한 번에 계산한다. 정밀도를 잃지 않으면서 깔끔한 그래디언트를 주기 때문에 모든 현대 분류 손실의 기본으로 쓰인다.
Stirling's approximation·스털링 근사
계승 자체를 계산하지 않고 계승의 로그를 구하는 공식: ln(n!) ≈ n·ln(n) − n + ½·ln(2πn). 앞 두 항 (n·ln(n) − n) 만으로도 보통 몇 퍼센트 오차로 정확하며, 거대한 계승의 자릿수를 손으로 추정할 수 있게 해준다.
logsumexp·logsumexp
지수 합의 로그를 수치적으로 안정하게 계산하는 함수. torch.logsumexp 와 scipy.special.logsumexp 로 제공된다. softmax, log_softmax, 거의 모든 확률 기반 손실 함수의 기본 부품.
⚠ "max-shift" 트릭 — log(Σ exp(xᵢ)) = max(x) + log(Σ exp(xᵢ − max(x))) — 내부 지수를 ≤ 0 로 유지하여 오버플로우와 언더플로우를 모두 피한다.