수학이 “얼마를 내든 이득"이라고 보증하는 게임 — 당신은 얼마까지 내시겠습니까




0. 서론: 수학 역사상 가장 비싼 동전 던지기

여기, 규칙이 한 줄짜리인 게임이 있습니다. 동전 하나를 앞면이 나올 때까지 던지는 것이 전부입니다. 그런데 이 게임의 적정 가격을 수학의 표준 잣대로 계산하면, 누구도 부정할 수 없는 답이 나옵니다. 무한대. 입장료로 1억 원을 불러도, 1조 원을 불러도, 계산기는 “그래도 남는 장사"라고 답합니다.

자, 그러면 당신은 이 게임에 얼마를 내시겠습니까. 전 재산? 아닐 겁니다. 규칙을 들여다보면 누구라도 머뭇거리게 되니까요. 이 게임은 절반의 확률로 단돈 2원을 쥐여 주고 끝나 버립니다. 실제로 이 게임에 만 원 이상을 내겠다는 사람은 찾기 어렵습니다. 한쪽에는 무한대라는 계산이, 다른 쪽에는 “기껏해야 몇천 원"이라는 직감이 있습니다. 둘의 간격은 문자 그대로 무한합니다. 도대체 어느 쪽이 거짓말을 하고 있을까요.

오늘 다룰 이야기는 상트페테르부르크의 역설(St. Petersburg Paradox)입니다. 1713년 베르누이 가문의 편지 한 통에서 태어나 300년 넘게 살아남은, ‘기댓값’이라는 잣대의 가장 유명한 헛발질이지요. 자매편 두 봉투 문제의 막바지에서 우리는 기댓값이 무한대로 발산하는 병리적인 게임을 잠깐 스쳐 지나간 적이 있습니다. 오늘은 그 모든 병리의 원조를 정면으로 마주합니다. 그리고 이 괴물을 길들이려던 시도 속에서 경제학이라는 학문의 주춧돌 하나가 놓이는 장면까지 보게 되실 겁니다.

이 글의 파이썬 코드 블록은 모두 접이식입니다. 코드가 부담스러우시면 펼치지 않고 그림과 숫자, 그리고 이야기만 따라오셔도 흐름은 온전히 이어집니다.




1. 게임의 규칙: 동전 하나, 상금은 두 배씩

게임은 이렇게 진행됩니다.

  1. 앞뒤가 반반인 공정한 동전 하나를 앞면이 나올 때까지 계속 던집니다.
  2. 첫 번째 던지기에서 바로 앞면이 나오면 상금은 2원입니다.
  3. 앞면이 한 번 늦게 나올 때마다 상금은 두 배가 됩니다. 두 번째에 나오면 4원, 세 번째면 8원, 네 번째면 16원…
  4. 앞면이 나오는 순간 게임은 끝나고, 그때까지 불어난 상금을 받습니다.

뒷면이 오래 버텨 줄수록 대박입니다. 뒷면이 9번 연속 나온 뒤 10번째에 앞면이 나오면 상금은 1,024원. 뒷면이 29번 버텨 주면 약 10억 원입니다. 동전이 연거푸 뒷면으로만 떨어지는 광경을 볼 수만 있다면, 당신은 그 자리에서 억만장자가 됩니다.

문제는 이 게임의 입장료입니다. 카지노가 얼마를 받아야 공정할까요? 계산을 시작하기 전에, 먼저 당신만의 답을 정해 두십시오. 당신이라면 이 게임에 최대 얼마까지 내시겠습니까? 마음속에 숫자 하나를 품으셨다면 — 글의 끝에서 그 숫자와 다시 만나게 됩니다.

자, 이제 수학의 답을 보러 갑시다. 이런 질문에 답하라고 만들어진 도구가 바로 기댓값(expected value)입니다. 거창한 말 같지만 뜻은 소박합니다. “이 게임을 아주 여러 번 반복하면, 한 판당 평균 얼마를 받게 되는가” — 그게 전부입니다.

연습 삼아 쉬운 게임에 한번 대 봅시다. 동전을 딱 한 번 던져 앞면이면 1,000원, 뒷면이면 꽝인 게임. 두 판에 한 번꼴로 1,000원을 받으니, 한 판당 평균 500원입니다. 그래서 이 게임의 공정한 입장료는 500원입니다. 더 싸면 손님이 이득, 더 비싸면 카지노가 이득. 복권과 보험과 카지노의 세계 전체가 이 잣대 하나로 설계됩니다.

이제 같은 잣대를 우리의 게임에 대 봅니다. 받을 수 있는 상금마다 “그 일이 일어날 확률"을 곱해서, 전부 더하면 됩니다.

  • 2원으로 끝날 확률: 첫 던지기가 앞면이면 되니 2분의 1. 평균에 보태는 몫은 2원의 절반, 1원.
  • 4원으로 끝날 확률: 뒷면 다음 앞면, 4분의 1. 보태는 몫은 4원의 4분의 1, 또 1원.
  • 8원으로 끝날 확률: 8분의 1로 줄지만 상금이 8원으로 커졌으니, 보태는 몫은 역시 1원.

눈치채셨을 겁니다. 상금은 두 배씩 커지고 확률은 절반씩 작아지니, 두 효과가 정확히 맞물려 모든 줄이 똑같이 1원씩을 보탭니다. 그리고 이 줄은 끝나지 않습니다.

$$\frac{1}{2}\times 2 \;+\; \frac{1}{4}\times 4 \;+\; \frac{1}{8}\times 8 \;+\;\cdots\;=\; 1+1+1+\cdots\;=\;\infty$$

기댓값, 무한대. 계산 어디에도 속임수는 없습니다. 그리고 기댓값이라는 잣대를 믿는다면 결론은 하나뿐입니다. 입장료가 얼마든 무조건 응하라. 1조 원을 내고 들어가도 ‘평균적으로는’ 남는 장사라는 뜻이니까요. 아래 그림은 이 무한대가 만들어지는 구조를 해부한 것입니다.

파이썬 코드 보기 (펼치기 / 접기)
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams.update({"figure.facecolor": "#0d1117", "savefig.facecolor": "#0d1117",
    "axes.facecolor": "#0d1117", "axes.edgecolor": "#30363d", "axes.labelcolor": "#e6edf3",
    "text.color": "#e6edf3", "axes.titlecolor": "#e6edf3", "xtick.color": "#8b949e",
    "ytick.color": "#8b949e", "grid.color": "#2a3340", "legend.facecolor": "#161b22",
    "legend.edgecolor": "#30363d", "legend.labelcolor": "#e6edf3"})

levels = np.arange(1, 11)        # the round on which the first head appears
prob = 0.5 ** levels             # chance the game ends on that round
prize = 2.0 ** levels            # prize paid on that round
contrib = prob * prize           # contribution to the expected value: always 1

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5))
labels = [f"{int(p):,}" for p in prize]

ax1.bar(levels, prob * 100, color="#4da3ff", edgecolor="#c9d1d9", width=0.62)
for lv, pc in zip(levels[:4], prob[:4] * 100):
    ax1.text(lv, pc + 1.3, f"{pc:.3g}%", ha="center", fontsize=10)
ax1.set_xticks(levels); ax1.set_xticklabels(labels, rotation=45)
ax1.set_xlabel("prize when the game ends (won)")
ax1.set_ylabel("chance of that ending [%]")
ax1.set_title("How games actually end: half stop at 2 won")
ax1.set_ylim(0, 58)
ax1.annotate("87.5% of all games\npay 8 won or less", xy=(3, 12.5), xytext=(5.2, 30),
             arrowprops=dict(arrowstyle="->", color="#ffd166", lw=1.6),
             color="#ffd166", fontsize=11)

ax2.bar(levels, contrib, color="#2a9d8f", edgecolor="#c9d1d9", width=0.62)
for lv in levels:
    ax2.text(lv, 1.04, "+1", ha="center", fontsize=10)
ax2.set_xticks(levels); ax2.set_xticklabels(labels, rotation=45)
ax2.set_xlim(0.3, 13.2); ax2.set_ylim(0, 1.5)
ax2.set_xlabel("prize level (won)")
ax2.set_ylabel("contribution to the average [won]")
ax2.set_title("...but every level adds exactly 1 won, forever")
ax2.text(11.0, 0.62, "+1 +1 +1 ...\nthe bricks\nnever stop", color="#ff5d5d",
         fontsize=12, ha="left")
plt.tight_layout()
plt.show()

How games actually end: half stop at 2 won · …but every level adds exactly 1 won, forever




2. 그런데 아무도 지갑을 열지 않는다

방금 그림의 왼쪽 패널은 게임이 실제로 어떻게 끝나는지를 보여 줍니다. 전체 판의 절반은 첫 던지기에서 2원으로 끝납니다. 4원 이하로 끝날 확률이 75%, 8원 이하가 87.5%. 막대는 오른쪽으로 갈수록 반토막 나며 순식간에 보이지도 않게 됩니다. 대박은 분명 존재하지만, 지독하게 멀리 있습니다. 상금이 100만 원을 넘으려면 뒷면이 19번 연속 나와야 하는데, 그 확률은 약 52만분의 1입니다.

오른쪽 패널이 역설의 심장입니다. 그 보잘것없어 보이는 줄 하나하나가, 기댓값 계산에서는 똑같이 1원짜리 벽돌입니다. 그리고 벽돌은 무한히 쌓입니다. 거의 일어나지 않는 일에 천문학적인 상금을 매겨 두면, ‘거의 0인 확률 × 거의 무한대인 상금’이라는 곱이 줄마다 1원씩 살아남아 끝없이 더해지는 것입니다.

그래서 머리로는 무한대를 인정해도, 몸은 따라 주지 않습니다. 과학철학자 이언 해킹(Ian Hacking)은 1980년에 이렇게 단언했습니다. “이 게임에 25달러라도 내겠다는 사람은 거의 없다.” 당신의 직감도 아마 비슷한 가격을 부르고 있을 겁니다.

여기서 이 역설의 모양이 또렷해집니다. 몬티 홀 문제에서는 직관이 틀렸고 수학이 옳았습니다. 그런데 이번에는 거꾸로 보입니다. 계산은 분명히 옳은데, 그 결론을 받아들이는 사람이 아무도 없습니다. 직감이 멍청해서일까요, 아니면 잣대가 무언가를 놓치고 있어서일까요. 말싸움은 그만하고, 가장 정직한 방법으로 확인해 봅시다. 직접 백만 판을 던져 보는 겁니다.




3. 백만 판의 실험: 무한대를 향해 기어가는 평균

기댓값의 정의가 “여러 번 반복했을 때의 한 판당 평균"이었으니, 정말로 여러 번 반복해 보면 됩니다. 컴퓨터에게 이 게임을 백만 판 시키고, 한 판이 끝날 때마다 “지금까지의 한 판당 평균 상금"이 어떻게 변해 가는지를 기록하겠습니다. 기댓값이 무한대라면 이 평균은 어떤 값에도 안주하지 못하고 계속 자라야 합니다. 정말 그럴까요? 그리고 자란다면, 얼마나 빨리 자랄까요?

똑같은 백만 판 실험을 서로 다른 우연으로 세 번 반복해 겹쳐 그렸습니다. 회색 점선은 잠시 후 설명할 이론적인 안내선입니다.

파이썬 코드 보기 (펼치기 / 접기)
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams.update({"figure.facecolor": "#0d1117", "savefig.facecolor": "#0d1117",
    "axes.facecolor": "#0d1117", "axes.edgecolor": "#30363d", "axes.labelcolor": "#e6edf3",
    "text.color": "#e6edf3", "axes.titlecolor": "#e6edf3", "xtick.color": "#8b949e",
    "ytick.color": "#8b949e", "grid.color": "#2a3340", "legend.facecolor": "#161b22",
    "legend.edgecolor": "#30363d", "legend.labelcolor": "#e6edf3"})

N = 1_000_000

def play_once(rng):
    prize = 2                     # the pot opens at 2 won
    while rng.random() < 0.5:     # tails -> double the pot and toss again
        prize *= 2
    return prize                  # heads -> game over, take the pot

def play_games(seed):
    rng = np.random.default_rng(seed)
    prizes = np.array([play_once(rng) for _ in range(N)])
    return prizes, np.cumsum(prizes) / np.arange(1, N + 1)

fig, ax = plt.subplots(figsize=(11, 5.5))
finals = []
for run, (seed, c) in enumerate(zip([11, 20, 1], ["#4da3ff", "#2a9d8f", "#e9c46a"]), 1):
    prizes, avg = play_games(seed)
    ax.semilogx(np.arange(1, N + 1), avg, color=c, lw=1.4, label=f"run {run}")
    finals.append(avg[-1])
    if run == 1:
        p1, a1 = prizes, avg

n = np.arange(10, N + 1)
ax.semilogx(n, np.log2(n), color="#8b949e", ls="--", lw=1.6,
            label=r"Feller's guide: $\log_2 n$")
ax.set_xlabel("number of games played so far (log scale)")
ax.set_ylabel("average prize per game so far [won]")
ax.set_title("One million games: the average never settles, and climbs at a crawl")
ax.legend(loc="upper left")
plt.tight_layout()
plt.show()

print(f"run 1 — {N:,} games")
print(f"  games ending at 2 won      : {np.mean(p1 == 2) * 100:.1f}%")
print(f"  games paying 8 won or less : {np.mean(p1 <= 8) * 100:.1f}%")
print(f"  biggest single prize       : {int(p1.max()):,} won")
print(f"  average over all games     : {a1[-1]:.1f} won   "
      f"(Feller's guide: log2(1,000,000) = {np.log2(N):.1f})")
print(f"  averages of runs 1 / 2 / 3 : {finals[0]:.1f} / {finals[1]:.1f} / {finals[2]:.1f} won")

One million games: the average never settles, and climbs at a crawl

run 1 — 1,000,000 games
  games ending at 2 won      : 50.0%
  games paying 8 won or less : 87.5%
  biggest single prize       : 4,194,304 won
  average over all games     : 24.7 won   (Feller's guide: log2(1,000,000) = 19.9)
  averages of runs 1 / 2 / 3 : 24.7 / 38.1 / 17.8 won

그림이 들려주는 이야기는 두 가지입니다.

첫째, 평균은 정말로 어떤 값에도 정착하지 않습니다. 보통의 게임이라면 — 주사위든 룰렛이든 — 판을 거듭할수록 평균이 기댓값 근처에 차분히 들러붙습니다. 이른바 큰 수의 법칙입니다. 그런데 이 게임의 평균은 영원히 어수선합니다. 한동안 슬금슬금 가라앉다가, 어쩌다 대박이 한 번 터지면 계단처럼 펄쩍 뛰어오르고, 다시 흔한 2원·4원짜리 판들에 눌려 천천히 내려앉습니다. 세 곡선은 서로 닮지도 않았습니다. 백만 판으로도 이 게임은 길들여지지 않은 것입니다.

둘째, 그럼에도 평균은 자라기는 합니다. 다만 잔인할 만큼 느리게. 출력된 통계를 보십시오. 백만 판을 던졌는데 한 판당 평균 상금은 24.7원, 나머지 두 실험에서도 약 38원과 18원 — 전부 푼돈입니다. 백만 판을 통틀어 가장 큰 대박이 약 420만 원(뒷면 21연속)이었으니 그럴 만도 합니다. 확률론의 거장 윌리엄 펠러(William Feller)는 이 느림보 성장의 속도를 정확히 재 주었습니다. n판을 몰아서 하면 한 판당 평균은 대략 $\log_2 n$원 — 쉽게 말해 판수를 제곱해야 평균이 겨우 두 배가 되는 속도로 자랍니다. 안내선의 눈높이가 백만 판에서 약 20원이니, 그 두 배인 40원을 보려면 백만 판의 제곱, 즉 1조 판이 필요합니다.

그러니 “기댓값이 무한대"라는 말은 거짓이 아닙니다. 평균은 정말로 한없이 자랍니다. 다만 그 무한대는, 당신이 살아서 만져 볼 수 있는 무한대가 아닙니다. 잣대는 옳은 말을 했지만, 그 말이 통하는 세계가 우리가 사는 세계가 아니었던 것이지요. 그렇다면 우리가 사는 세계의 가격표는 어떻게 매겨야 할까요. 300년 전, 한 수학자 가문의 편지함에서 그 답이 모양을 갖추기 시작합니다.




4. 막간: 왜 하필 ‘상트페테르부르크’인가

이 문제의 출생지는 사실 러시아가 아닙니다. 1713년 9월, 스위스 바젤의 수학자 니콜라우스 베르누이(Nicolas Bernoulli)가 파리의 확률론자 피에르 레몽 드 몽모르(Pierre Rémond de Montmort)에게 보낸 편지에 처음 등장합니다. 베르누이라는 성이 익숙하시다면, 맞습니다. 미적분의 초창기를 주름잡은 야코프와 요한, 유체역학의 다니엘까지 — 한 집안에서 일류 수학자가 줄줄이 쏟아진 그 전설의 가문입니다.

여담 — 원조는 동전이 아니라 주사위. 니콜라우스가 편지에 적은 원래 버전은 주사위로 6이 나올 때까지 던지는 게임이었습니다. 상금이 갈수록 불어나는 뼈대는 같았지요. 오늘날처럼 동전 던지기로 다듬어진 것은, 잠시 후 등장할 크라메르의 1728년 편지에서입니다.

문제는 25년 가까이 수학자들의 편지 속을 떠돌며 사람들을 괴롭혔습니다. 그러다 1738년, 니콜라우스의 사촌 다니엘 베르누이(Daniel Bernoulli)가 마침내 해법을 담은 논문을 발표합니다. 젊은 다니엘이 몸담았던 곳이 러시아 제국의 상트페테르부르크 학술원이었고, 논문이 실린 곳도 바로 그 학술원의 논문집이었습니다. 그래서 이 역설의 이름은 문제가 태어난 바젤도, 편지가 배달된 파리도 아닌, 해법이 출판된 도시의 것이 되었습니다.

다니엘의 처방은 한 문장으로 요약됩니다. 그리고 이 한 문장이, 과장 없이, 훗날 경제학의 물줄기를 바꿉니다.




5. 베르누이의 처방: 같은 돈이라도 무게가 다르다

다니엘의 출발점은 소박한 관찰입니다. 우리는 아까 상금의 ‘액수’에 확률을 곱했습니다. 그런데 — 돈의 액수가 곧 돈의 가치일까요?

목마른 사람에게 물 한 잔은 천금 같습니다. 두 잔째는 고맙고, 다섯 잔째는 그저 그렇고, 열 잔째는 고문입니다. 돈도 마찬가지입니다. 전 재산이 천 원인 사람에게 100만 원은 인생이 바뀌는 돈이지만, 재산이 수백조 원인 일론 머스크에게 같은 100만 원은 눈금에도 잡히지 않는 잔돈입니다. 이미 가진 것이 많을수록, 새로 얹히는 한 장의 기쁨은 작아집니다. 훗날 경제학이 ‘한계효용 체감’이라는 이름표를 붙이는 바로 그 직관입니다.

그래서 다니엘은 잣대를 바꿉니다. 상금의 액수가 아니라, 상금이 주는 만족 — 그가 붙인 이름으로는 효용(utility) — 에 확률을 곱하자는 것입니다. 그가 고른 효용의 모양을 일반인의 언어로 옮기면 이렇습니다. 행복은 돈의 액수가 아니라 돈의 자릿수를 따라 자란다. 재산이 두 배가 될 때마다 — 100만 원이 200만 원이 되든, 1억 원이 2억 원이 되든 — 기쁨은 똑같이 ‘한 칸’씩 오른다는 뜻입니다. (수학에 익숙한 분께는: 로그입니다.)

이 새 자로 게임을 다시 재 봅시다. 상금 2원은 행복 1칸, 4원은 2칸, 8원은 3칸, 16원은 4칸… 아까는 상금이 2원, 4원, 8원으로 곱절씩 폭주했지만, 행복은 1칸, 2칸, 3칸으로 한 걸음씩만 걷습니다. 폭주하던 상금이 얌전해지는 순간, 무한대도 사라집니다. 기대 ‘행복’을 계산하면 (1/2 × 1칸) + (1/4 × 2칸) + (1/8 × 3칸) + … 인데, 이 합은 폭발하지 않고 정확히 2칸으로 깔끔하게 수렴합니다. 이렇게 액수 대신 효용에 확률을 곱해 낸 평균을 기대 효용(expected utility)이라고 부릅니다. 그리고 ‘행복 2칸’에 해당하는 현금은, 2를 두 번 거듭한 4원입니다.

무한대였던 가격표가 단돈 4원이 됐습니다. (빈손으로 게임을 받는 사람 기준의 값입니다. 가진 재산이 많을수록 이 값은 아주 천천히 커지지만, 현실의 어떤 부자에게도 몇십 원 수준에 그칩니다.) 황당하리만치 짠 값이지만, 곱씹어 보면 이쪽이 오히려 우리 직감과 같은 편입니다. 두 판에 한 판은 2원으로 끝나는 게임이니까요.

여담 — 사실 첫 타자는 따로 있었다. 다니엘보다 10년 앞선 1728년, 제네바의 수학자 가브리엘 크라메르(Gabriel Cramér)가 니콜라우스에게 보낸 편지에 거의 같은 생각이 담겨 있었습니다. “수학자들은 돈을 그 양으로 재지만, 상식 있는 사람은 그 쓸모로 잰다.” 크라메르는 자기 식의 잣대(제곱근 효용)로 게임의 값을 몇 푼 수준까지 끌어내렸고, 다니엘도 논문 말미에 이 편지를 소개하며 그의 선구를 인정했습니다.

여담 — 약은 약일 뿐, 만병통치약은 아니다. 1934년 수학자 카를 멩거(Karl Menger)는 짓궂은 후속편을 내놓습니다. 상금이 ‘돈 2배씩’이 아니라 ‘행복 2배씩’ 불어나도록 게임을 다시 설계하면 — 이른바 슈퍼 상트페테르부르크 게임 — 로그 자를 들이대도 기대 행복이 도로 무한대가 됩니다. 효용이라는 약은 이 게임 하나를 잠재웠을 뿐, ‘무한대’라는 병원체를 박멸하지는 못한 것입니다. 그 뒤로 “효용에는 천장이 있어야 한다"는 처방이 추가됩니다.




6. 더 김빠지는 처방: 그 카지노, 잔고는 확인하셨습니까

효용까지 가지 않아도 무한대의 김을 빼는, 지극히 세속적인 관찰이 하나 더 있습니다. 무한대를 쌓아 올리던 1원짜리 벽돌들을 다시 보십시오. 뒤로 갈수록 그 벽돌은 천문학적인 상금이 책임지고 있습니다. 그런데 — 그 돈, 누가 줍니까?

뒷면이 39번 연속 나오면 카지노는 약 1조 1천억 원을 내줘야 합니다. 49번이면 1,000조 원이 넘습니다. 세상의 어떤 카지노도, 어떤 정부도 이 약속을 끝까지 지킬 수 없습니다. 그리고 지급 한도가 생기는 순간, 기댓값 계산은 전혀 다른 답을 내놓습니다. 한도 위로는 상금이 더 자라지 못하니, 그 뒤의 줄들은 1원짜리 벽돌 대신 급격히 쪼그라드는 푼돈만 보태게 되거든요. 계산해 보면 결과는 충격적으로 시시합니다. 카지노의 금고가 두 배 커질 때마다, 공정한 입장료는 딱 1원씩 오릅니다.

  • 약 100만 원까지 지급을 보증하는 동네 오락실 — 공정 입장료 21원
  • 약 1조 원까지 보증하는 대기업 카지노 — 41원
  • 지구 위의 부를 모조리 긁어모은 것보다도 큰 우주적 은행(약 백 경 원) — 61원

금고가 백만 배 커질 때마다 입장료는 고작 20원씩 오릅니다. 결국 “기댓값 무한대"라는 답은 무한한 잔고를 가진 은행이 무한히 많은 판을 보증할 때에만 성립하는 숫자였던 셈입니다. 그런 은행은 우주 어디에도 없습니다.

아래 그림에 지금까지의 두 처방을 나란히 담았습니다. 왼쪽은 베르누이의 자 — 멈출 줄 모르고 솟구치는 상금(빨간 직선)과, 그 곁에서 한 칸씩만 오르는 행복(파란 곡선)의 동상이몽. 오른쪽은 유한한 은행 — 금고가 백만 배씩 커져도 입장료는 거의 꿈쩍하지 않는 풍경입니다.

파이썬 코드 보기 (펼치기 / 접기)
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams.update({"figure.facecolor": "#0d1117", "savefig.facecolor": "#0d1117",
    "axes.facecolor": "#0d1117", "axes.edgecolor": "#30363d", "axes.labelcolor": "#e6edf3",
    "text.color": "#e6edf3", "axes.titlecolor": "#e6edf3", "xtick.color": "#8b949e",
    "ytick.color": "#8b949e", "grid.color": "#2a3340", "legend.facecolor": "#161b22",
    "legend.edgecolor": "#30363d", "legend.labelcolor": "#e6edf3"})

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5))

# (a) Bernoulli's ruler: the prize itself rockets, the felt value crawls
x = np.linspace(1, 1100, 800)
ax1.plot(x, np.log2(x), color="#4da3ff", lw=2.5, zorder=3)
marks = 2.0 ** np.arange(1, 11)                    # 2, 4, 8, ..., 1024
ax1.plot(marks, np.log2(marks), "o", color="#ffd166", ms=6, zorder=5)
for m in marks[:-1]:                               # staircase: equal risers everywhere
    ax1.plot([m, 2 * m], [np.log2(m), np.log2(m)], color="#8b949e", ls=":", lw=1)
    ax1.plot([2 * m, 2 * m], [np.log2(m), np.log2(m) + 1], color="#ffd166", lw=2)
ax1.annotate("512 -> 1024 won:\nhalf the axis,\nstill ONE notch", xy=(1024, 9.55),
             xytext=(640, 7.1), color="#ffd166", fontsize=10,
             arrowprops=dict(arrowstyle="->", color="#ffd166", lw=1.6))
ax1.text(220, 9.2, "the felt value (curve)\nlies down", color="#4da3ff",
         fontsize=11, ha="center")
ax1.set_xlabel("money [won]")
ax1.set_ylabel("felt value [notches]  (log2 of money)", color="#4da3ff")
ax1.tick_params(axis="y", labelcolor="#4da3ff")
ax1.set_title("Bernoulli's ruler: the prize rockets, the felt value crawls")
ax1.set_xlim(0, 1100); ax1.set_ylim(0, 11)

ax1r = ax1.twinx()                                 # the raw prize, for contrast
ax1r.plot(x, x, color="#ff5d5d", lw=2, ls="--")
ax1r.text(430, 330, "the prize itself (straight line)\nkeeps shooting up", color="#ff5d5d",
          fontsize=10, ha="center", va="top", rotation=37)
ax1r.set_ylabel("the prize itself [won]", color="#ff5d5d")
ax1r.tick_params(axis="y", labelcolor="#ff5d5d")
ax1r.set_ylim(0, 1100)

# (b) an honest bank: cap the payout at 2^K won -> fair entry fee = K+1 won
K = np.arange(10, 71)
ax2.semilogx(2.0 ** K, K + 1, color="#2a9d8f", lw=2.5)
points = [(20, "local arcade\n(~1 million won)", "#4da3ff", (2.0 ** 13, 33)),
          (40, "mega casino\n(~1 trillion won)", "#ffd166", (2.0 ** 33, 56)),
          (60, "all money on Earth\n(~10^18 won)", "#ff5d5d", (2.0 ** 50, 76))]
for k, name, c, txt in points:
    ax2.plot(2.0 ** k, k + 1, "o", color=c, ms=8, zorder=5)
    ax2.annotate(f"{name}\nfair fee = {k + 1} won", xy=(2.0 ** k, k + 1), xytext=txt,
                 color=c, fontsize=10, ha="center",
                 arrowprops=dict(arrowstyle="->", color=c, lw=1.5))
ax2.set_xlabel("the bank's maximum payout [won]  (log scale)")
ax2.set_ylabel("fair entry fee [won]")
ax2.set_title("An honest bank: a million times richer, only 20 won more")
ax2.set_ylim(0, 90)
plt.tight_layout()
plt.show()

eu = sum(k / 2.0 ** k for k in range(1, 200))
print("Bernoulli's ruler:")
print(f"  expected happiness = {eu:.2f} notches  ->  cash equivalent 2^2 = 4 won")
print()
print("an honest bank (payout capped at 2^K won -> fair entry fee = K+1 won):")
for k, name in [(20, "local arcade"), (40, "mega casino"), (60, "all money on Earth")]:
    print(f"  cap 2^{k} = {2 ** k:>26,} won ({name})  ->  fair fee = {k + 1} won")

Bernoulli’s ruler: the prize rockets, the felt value crawls · An honest bank: a million times richer, only 20 won more

Bernoulli's ruler:
  expected happiness = 2.00 notches  ->  cash equivalent 2^2 = 4 won

an honest bank (payout capped at 2^K won -> fair entry fee = K+1 won):
  cap 2^20 =                  1,048,576 won (local arcade)  ->  fair fee = 21 won
  cap 2^40 =          1,099,511,627,776 won (mega casino)  ->  fair fee = 41 won
  cap 2^60 =  1,152,921,504,606,846,976 won (all money on Earth)  ->  fair fee = 61 won

왼쪽 그림의 빨간 직선은 상금 그 자체입니다 — 멈출 줄 모르고 곧장 솟습니다. 같은 돈을 베르누이의 자로 잰 것이 파란 곡선인데, 위로 갈수록 자꾸 누워 버립니다. 2원에서 4원으로, 512원에서 1,024원으로, 가로축에서 아무리 큰 걸음을 떼도 행복은 똑같이 한 칸씩만 오릅니다. 이 두 선의 어긋남이 역설을 해부합니다. 기댓값은 빨간 자로 잰 무한대였고, 우리의 직감은 처음부터 파란 자로 재고 있었던 것입니다. 오른쪽 그림의 가로축은 그보다 더 험합니다. 100만 원에서 100경 원까지, 한 눈금이 백만 배인 로그 눈금인데도 공정 입장료는 21원에서 61원으로 기어갈 뿐입니다. 무한대라는 괴물은, 유한한 세계에 발을 딛는 순간 푼돈이 됩니다.




7. 대단원: 잣대가 닿지 않는 곳

이제 역설을 처음부터 끝까지 한 호흡으로 정리할 수 있습니다.

기댓값이 무한대라는 계산은 옳습니다. 속임수도, 실수도 없습니다. 하지만 그 숫자가 의미를 가지려면 두 가지 무한이 필요합니다. 무한히 많은 판 — 평균이 무한대까지 자랄 시간 — 과 무한히 깊은 금고 — 천문학적 상금의 지급 보증 — 입니다. 우리의 인생도, 카지노의 잔고도 유한합니다. 그 유한한 세계에서 당신이 실제로 만나는 것은 ‘평균’이 아니라 단 한 번의 결과이고, 그 결과는 절반의 확률로 2원입니다. 직감은 처음부터 이것을 알고 있었습니다. 기댓값이라는 잣대가 틀린 게 아니라, 잣대가 통하는 세계의 바깥에 이 게임이 서 있었던 것입니다. 무한한 기댓값과 유한한 인간 — 이 한 줄의 어긋남이 역설의 전부입니다.

그리고 이 퍼즐은 푼돈 게임 하나로 끝나지 않았습니다. 다니엘 베르누이가 역설을 잠재우려고 벼린 ‘효용’이라는 개념 — 같은 돈이라도 처지에 따라 무게가 다르다는 그 생각은, 같은 논문 안에서 이미 언제 상인이 기꺼이 보험료를 물고 보험에 드는 것이 합리적인지까지 설명해 냅니다. 공교롭게도 그 예시의 주인공마저 상트페테르부르크의 상인이었지요. 위험을 피하는 인간, 가질수록 가벼워지는 돈 — 이 직관은 200여 년 뒤 폰 노이만과 모르겐슈테른의 기대효용이론으로 다듬어져, 현대 경제학과 금융학의 주춧돌이 됩니다. 오늘 우리가 어떤 내기 앞에서 산술 평균만 보지 않고 제 주머니 사정과, 위험을 대하는 제 태도와, 실패했을 때의 타격까지 함께 저울에 올리는 것도, 따지고 보면 이 푼돈 게임이 남긴 유산입니다. 동전 던지기 퍼즐 하나가 학문 하나의 산파가 된 셈입니다.

세 줄 요약

  1. 상금은 두 배씩, 확률은 절반씩 — 모든 줄이 평균에 1원씩 보태므로 기댓값은 무한대다. 계산에는 아무 잘못이 없다.
  2. 그러나 그 무한대는 무한한 판수와 무한한 잔고 위에서만 사는 숫자다. 백만 판을 던져도 평균은 몇십 원, 전 세계의 부보다 큰 금고를 가진 은행을 상대해도 공정 입장료는 61원이다.
  3. 베르누이의 답: 돈이 아니라 돈의 쓸모(효용)로 재라. 행복이 돈의 자릿수를 따라 자란다면 이 게임의 가치는 몇 원에 불과하다 — 그리고 이 처방이 훗날 경제학의 주춧돌이 되었다.

다음에 누군가 “기댓값이 이만큼이니 무조건 이득"이라며 당신을 설득하려 들거든, 조용히 두 가지만 되물어 보십시오. “그 평균, 몇 판을 해야 만날 수 있습니까?” 그리고 “그 상금, 누가 지급을 보증합니까?” 이 두 질문을 품고 계시다면, 당신은 이미 300년 전의 베르누이와 같은 편에 서 있는 것입니다.

그래서, 1절에서 마음속에 품어 두셨던 그 숫자로 돌아갑니다. 당신의 입장료는 얼마였습니까. 무한대가 아니라 푼돈이었다면 — 축하드립니다. 당신의 직감은 수학 300년 치를 이미 알고 있었던 겁니다. 이제 당신은 거기에 정확한 가격표까지 붙일 수 있습니다. 4원과 61원 사이, 어디쯤입니다.