세상에서 가장 지루한 수를 찾아낸 순간, 그 수는 더 이상 지루하지 않습니다




0. 서론: 런던 교외의 택시 번호 1729

1918년 무렵의 어느 날, 영국의 수학자 G. H. 하디는 런던 교외 퍼트니(Putney)의 요양원으로 병문안을 갑니다. 침대에 누워 있던 사람은 인도에서 온 천재 수학자 스리니바사 라마누잔. 결핵으로 몸이 많이 상한 상태였습니다. 그 날의 짧은 대화를 하디는 훗날(1940년) 자신의 강연집에 직접 적어 두었는데, 수학의 역사에서 가장 사랑받는 일화 중 하나가 바로 이 대목입니다.

나는 1729번 택시를 타고 갔는데, 그 번호가 영 심심한 수 같아서, 불길한 징조가 아니기를 바란다고 말을 건넸다. 그러자 그가 답했다. “아닙니다. 아주 흥미로운 수예요. 두 세제곱수의 합으로, 두 가지 서로 다른 방법으로 쓸 수 있는 가장 작은 수거든요.”

병상에서 즉석으로 나온 그 말을 식으로 적으면 이렇습니다.

$$1729 = 1^3 + 12^3 = 9^3 + 10^3$$

확인은 초등 산수입니다. $1 + 1728 = 1729$ 그리고 $729 + 1000 = 1729$. 같은 수에 도착하는 전혀 다른 두 갈래 길이 있고, 이런 일이 일어나는 수 가운데 1729가 막내라는 것이지요. 덕분에 1729에는 아예 택시수(Taxicab number) 라는 별명이 붙었고, 하디-라마누잔 수라고도 불립니다.

그런데 이 유명한 일화를 뒤집어 보면 질문이 하나 남습니다. 라마누잔급의 변호사가 붙으니 “심심한 수” 1729도 한 방에 스타가 됐습니다. 그렇다면 변호가 불가능한 수, 그러니까 정말로 아무 특징 없는 ‘지루한 수’라는 게 세상에 있기는 할까요?

놀랍게도 수학자들 사이에는 이 질문에 대한 농담 반 진담 반의 답이 오래전부터 전해 내려옵니다. “지루한 수는 단 하나도 없다. 그리고 그걸 증명할 수 있다.” 이것이 오늘의 주인공, 흥미로운 수 역설(Interesting Number Paradox) 입니다. 이번 글에서는 이 수상한 증명을 끝까지 따라가 봅니다. 먼저 증명을 구경하고(1장), 첫 번째 부품을 두 각도에서 뜯어보고(2~3장), 두 번째 부품을 검사한 다음(4장), 마지막에 범인을 잡습니다(5장). 무서운 수식은 쓰지 않습니다. 우리가 쓸 도구는 줄 세우기, 개수 세기, 그리고 컴퓨터로 수천 개의 수를 채점해 보는 작은 실험 — 이게 전부입니다.

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




1. 가장 뻔뻔한 정리: 모든 수는 흥미롭다

1945년 4월, 점잖기로 유명한 미국의 수학 학술지(American Mathematical Monthly)에 짤막한 글 하나가 실립니다. 수학자 에드윈 베켄바흐(Edwin Beckenbach)가 쓴 “흥미로운 정수들(Interesting Integers)“이라는 노트로, 이 역설이 활자로 남은 가장 오래된 기록입니다. 주장은 이렇습니다.

정리(라고 주장됨). 모든 자연수 1, 2, 3, 4, … 는 흥미롭다.

증명이라는 것도 따라옵니다. 한 걸음씩 가 보겠습니다.

1단계. 흥미롭지 않은 수, 그러니까 ‘지루한 수’가 하나라도 있다고 가정해 봅시다.

2단계. 지루한 수가 있다면, 지루한 수들을 전부 모아서 작은 것부터 한 줄로 세울 수 있습니다. 그리고 자연수를 모아 놓은 줄에는 — 텅 빈 줄만 아니라면 — 반드시 맨 앞에 선 수(가장 작은 수) 가 있습니다.

3단계. 그 맨 앞의 수를 $m$ 이라고 부르겠습니다. $m$ 은 “세상에서 가장 작은 지루한 수"입니다.

4단계. 그런데 잠깐. “세상에서 가장 작은 지루한 수"라니, 그것 자체가 엄청나게 희귀한 타이틀 아닌가요? 무한히 많은 수 가운데 그 타이틀을 가진 수는 딱 하나뿐입니다. 친구에게 자랑해도 될 만한 특징입니다. 그러니까 $m$ 은… 흥미로운 수입니다.

5단계. 모순입니다. $m$ 은 지루한 수들의 줄에서 뽑아 왔는데, 흥미로워져 버렸으니까요. 무언가 잘못됐고, 잘못될 수 있는 곳은 1단계의 가정뿐입니다. 따라서 지루한 수는 존재하지 않습니다. 증명 끝.

어딘가 사기당한 기분이 드시지요? 정상입니다. 그 직감을 끝까지 밀고 가는 것이 이 글의 목표입니다.

이 논증은 발표 이후 꾸준히 사랑받았습니다. 1955년에는 콘스턴스 리드의 베스트셀러 교양서 “0에서 무한대까지(From Zero to Infinity)“에 실렸고, 1958년에는 마틴 가드너가 사이언티픽 아메리칸의 그 유명한 수학 칼럼에서 소개하며 대중적으로 널리 퍼졌습니다. 다만 가드너는 이것을 정리가 아니라 오류(fallacy) 모음 — 그럴듯해 보이지만 증명 어딘가에 교묘한 잘못이 숨어 있는 주장들 — 의 하나로 소개했습니다. 즉 수학계의 공식 입장은 “어딘가 틀렸다"입니다.

그런데, 어디가요? 한눈에 짚어 내기가 의외로 어렵습니다. 이 증명은 크게 부품 세 개로 조립되어 있습니다.

  1. ‘흥미롭다’는 수가 가질 수 있는 속성이다. (그래서 ‘지루한 수들’을 모을 수 있다.)
  2. 자연수의 줄에는 반드시 맨 앞이 있다. (그래서 가장 작은 지루한 수 $m$ 을 뽑을 수 있다.)
  3. “가장 작은 지루한 수"라는 타이틀은 그 자체로 흥미롭다. (그래서 모순이 터진다.)

범인을 잡으려면 부품을 하나씩 분해해서 검사해 봐야겠지요. 첫 번째 부품부터 시작합니다.




2. 첫 번째 부품: ‘흥미롭다’는 정말 수의 속성일까 — 1729의 변호

1729로 돌아가 봅시다. 솔직히 말해, 라마누잔의 한마디를 듣기 전까지 1729는 누가 봐도 평범한 수였습니다. 제곱수도 아니고, 소수도 아니고(7로 나누어집니다), 기념일이나 비밀번호에 쓸 만한 모양새도 아닙니다. 세계 최고 수준의 수학자였던 하디조차 “심심한 수"라고 불렀을 정도니까요.

그런데 변호사 라마누잔이 나서자 상황이 한 방에 뒤집혔습니다. 변호의 논리는 이렇습니다. 어떤 수들은 두 세제곱수의 합으로 쓸 수 있습니다. 예를 들어 $9 = 1 + 8 = 1^3 + 2^3$ 처럼요. 그런데 그렇게 쓸 수 있는 수들도 거의 전부는 쓰는 방법이 한 가지뿐입니다. 1729는 그 방법이 두 가지나 되는, 그러면서도 가장 작은 수라는 것이지요.

정말 그런지는 말로 다툴 필요가 없습니다. 컴퓨터에게 25,000까지 몽땅 세어 보라고 시키면 되니까요.

파이썬 코드 보기 (펼치기 / 접기)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

# 한글 차트용 폰트 자동 등록(윈도우=맑은 고딕). 없으면 시스템 한글 폰트를 이름으로 탐색,
# 그래도 없으면 라벨을 영어로 폴백(두부 방지, OS 이식성).
_has_kr, KFONT = False, "DejaVu Sans"
for _fp in [r"C:\Windows\Fonts\malgun.ttf",
            "/System/Library/Fonts/AppleSDGothicNeo.ttc",
            "/usr/share/fonts/truetype/nanum/NanumGothic.ttf",
            "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
            "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc"]:
    try:
        fm.fontManager.addfont(_fp)
        KFONT = fm.FontProperties(fname=_fp).get_name()
        _has_kr = True
        break
    except Exception:
        continue
if not _has_kr:
    _avail = {f.name for f in fm.fontManager.ttflist}
    for _n in ["Malgun Gothic", "AppleGothic", "Apple SD Gothic Neo", "NanumGothic",
               "Noto Sans CJK KR", "Noto Sans KR", "Source Han Sans KR", "UnDotum"]:
        if _n in _avail:
            KFONT, _has_kr = _n, True
            break
if _has_kr:
    plt.rcParams["font.family"] = KFONT
plt.rcParams["axes.unicode_minus"] = False

def L(ko, en):
    return ko if _has_kr else en

DARK, LIGHT = "#0d1117", "#e6edf3"
BLUE, ORANGE, YELLOW, GREY, RED, GREEN = "#5dade2", "#e08a3c", "#f1c40f", "#7d8590", "#e74c3c", "#2ecc71"

# 1729: 두 양의 세제곱수의 합으로 '두 가지 방법'으로 쓸 수 있는 가장 작은 수
from collections import defaultdict

LIMIT = 25000                            # 이 한도 안의 수만 전수 조사
ways = defaultdict(list)                 # 합 -> 그 합을 만드는 (a, b) 목록 (1 <= a <= b)
top = round(LIMIT ** (1 / 3)) + 1
for a in range(1, top + 1):
    for b in range(a, top + 1):
        s = a ** 3 + b ** 3
        if s <= LIMIT:
            ways[s].append((a, b))

single = sorted(s for s, ab in ways.items() if len(ab) == 1)
double = sorted(s for s, ab in ways.items() if len(ab) >= 2)

print(f"{LIMIT:,} 이하에서 '두 양의 세제곱수의 합'으로 쓸 수 있는 수: {len(ways):,}개")
print(f"그중 두 가지 방법으로 쓸 수 있는 수: 단 {len(double)}\n")
for s in double:
    reps = "  =  ".join(f"{a}³ + {b}³" for a, b in ways[s])
    print(f"  {s:>6,}  =  {reps}")

fig = plt.figure(figsize=(13, 5.6))
fig.patch.set_facecolor(DARK)
gs = fig.add_gridspec(1, 2, width_ratios=[1.0, 1.62], wspace=0.24,
                      left=0.06, right=0.975, top=0.80, bottom=0.13)

# (왼쪽) 곡선 x³ + y³ = 1729 위에 정확히 올라앉는 두 쌍의 정수 좌표
axL = fig.add_subplot(gs[0, 0])
axL.set_facecolor(DARK)
xx = np.linspace(0, 1729 ** (1 / 3), 400)
axL.plot(xx, np.cbrt(1729 - xx ** 3), color=BLUE, lw=2.4, zorder=3)
gx, gy = np.meshgrid(np.arange(14), np.arange(14))
axL.scatter(gx, gy, s=7, color="#2b3138", zorder=1)
for (px, py), col in [((1, 12), RED), ((9, 10), YELLOW)]:
    axL.scatter([px, py], [py, px], s=130, color=col, edgecolor=LIGHT,
                linewidth=0.9, zorder=5)
axL.annotate("1³ + 12³", xy=(1, 12), xytext=(2.7, 12.3), color=RED,
             fontsize=13, fontweight="bold")
axL.annotate("9³ + 10³", xy=(9, 10), xytext=(9.7, 11.2), color=YELLOW,
             fontsize=13, fontweight="bold")
axL.set_xlim(-0.6, 13.6)
axL.set_ylim(-0.6, 13.6)
axL.set_aspect("equal")
axL.set_title(L("곡선 x³ + y³ = 1729 를 통과하는 정수 좌표", "Integer points on x³ + y³ = 1729"),
              color=LIGHT, fontsize=12.5, pad=10)

# (오른쪽) 25,000 이하의 모든 '두 세제곱수의 합'을 가짓수별로 늘어놓기
axR = fig.add_subplot(gs[0, 1])
axR.set_facecolor(DARK)
rng = np.random.default_rng(1729)
axR.scatter(single, 1 + rng.uniform(-0.16, 0.16, len(single)),
            s=9, color=GREY, alpha=0.5, lw=0)
for s in double:
    axR.plot([s, s], [0.55, 1.97], color=ORANGE, lw=1.1, alpha=0.75, zorder=2)
    axR.scatter([s], [2], marker="*", s=340, color=YELLOW, edgecolor=DARK,
                lw=0.6, zorder=5)
    axR.annotate(f"{s:,}", xy=(s, 2), xytext=(s, 2.22), color=YELLOW,
                 ha="center", fontsize=11)
axR.annotate(L("첫 번째 주인공 = 1729", "the first one = 1729"),
             xy=(1850, 2.06), xytext=(7300, 2.62), color=LIGHT, fontsize=12.5,
             arrowprops=dict(arrowstyle="->", color=LIGHT, lw=1.1))
axR.set_ylim(0.4, 2.95)
axR.set_yticks([1, 2])
axR.set_yticklabels([L("1가지 방법", "1 way"), L("2가지 방법", "2 ways")],
                    color=LIGHT, fontsize=11.5)
axR.set_xlabel(L("두 양의 세제곱수의 합으로 만들어지는 수", "sums of two positive cubes"),
               color=LIGHT, fontsize=11.5)
axR.set_title(L("같은 수에 도착하는 길의 가짓수 (25,000 이하)", "How many ways to reach each sum (≤ 25,000)"),
              color=LIGHT, fontsize=12.5, pad=10)

for ax in (axL, axR):
    for sp in ax.spines.values():
        sp.set_color("#3a414a")
    ax.tick_params(colors=GREY)

fig.suptitle(L("1729 — 두 세제곱수의 합으로 '두 번' 쓸 수 있는 가장 작은 수",
               "1729 — the smallest sum of two cubes in two different ways"),
             color=LIGHT, fontsize=15.5, fontweight="bold", y=0.95)
plt.show()
25,000 이하에서 '두 양의 세제곱수의 합'으로 쓸 수 있는 수: 373개
그중 두 가지 방법으로 쓸 수 있는 수: 단 4개

   1,729  =  1³ + 12³  =  9³ + 10³
   4,104  =  2³ + 16³  =  9³ + 15³
  13,832  =  2³ + 24³  =  18³ + 20³
  20,683  =  10³ + 27³  =  19³ + 24³

두 부분으로 된 그림. 왼쪽은 곡선 x³+y³=1729가 정수 좌표 (1, 12)와 (9, 10)을 정확히 통과하는 모습으로, 1729로 가는 서로 다른 두 갈래 길을 보여 준다. 오른쪽은 25,000 이하에서 두 양의 세제곱수의 합으로 쓸 수 있는 373개의 수를 늘어놓은 것으로, 대부분은 한 가지 방법뿐이고 두 가지 방법으로 쓸 수 있는 수는 1729, 4104, 13832, 20683 네 개뿐이며 그중 가장 작은 1729가 노란 별과 화살표로 강조되어 있다.

결과를 읽어 봅시다. 25,000 이하에서 두 양의 세제곱수의 합으로 쓸 수 있는 수는 모두 373개. 오른쪽 그림 아래쪽에 회색 점으로 깔린 다수가 전부 “한 가지 방법"짜리입니다. 그중 “두 가지 방법"이 되는 수는 딱 4개 — 1729, 4104, 13832, 20683 — 뿐이고, 그 맨 앞에 1729가 있습니다. 왼쪽 그림은 같은 사실을 다른 각도에서 보여 줍니다. 곡선 $x^3 + y^3 = 1729$ 가 정수 좌표를 정확히 통과하는 사건이 두 번 일어나는 것이지요. (대각선 반대편의 거울상까지 치면 점은 네 개입니다만, 조합으로는 같은 두 가지입니다.)

여담을 셋만 얹겠습니다. 첫째, 사실 이 성질은 라마누잔이 처음 발견한 것이 아닙니다. 프랑스의 수학자 프레니클 드 베시(Frénicle de Bessy)가 1657년에 이미 기록해 두었습니다. 라마누잔보다 260여 년 앞선 것인데, 그렇다고 일화의 가치가 깎이지는 않습니다. 병상에서 그 사실이 즉석에서 튀어나왔다는 것 자체가 이미 명장면이니까요. 둘째, ‘양의’ 세제곱수라는 조건이 은근히 중요합니다. 음수까지 허용하면 $91 = 3^3 + 4^3 = 6^3 + (-5)^3$ 이라서, 91이 훨씬 먼저 두 가지 방법을 갖게 됩니다. 셋째, 1729의 이력서에는 다른 줄도 있습니다. 소인수분해하면 $1729 = 7 \times 13 \times 19$ 인데, 자릿수를 더하면 $1 + 7 + 2 + 9 = 19$ 가 되고, 1729는 이 19로 나누어떨어집니다($1729 = 19 \times 91$). 게다가 그 몫 91은 남은 두 소인수의 곱($7 \times 13$)입니다. 1729는 또 ‘소수 판별 시험을 속이는 가짜 소수’로 악명 높은 카마이클 수의 세 번째 멤버이기도 합니다(561, 1105 다음). 변호사가 작정하고 뒤지면 변호 거리가 줄줄이 나오는 수인 셈입니다.

정리하면, 첫 번째 부품은 절반쯤 합격입니다. ‘흥미롭다’의 정확한 정의는 아직 흐릿하지만, 적어도 “이 수에는 이런 특징이 있다"라고 변호하는 일 자체는 분명히 가능합니다. 그렇다면 자연스럽게 궁금해집니다. 모든 수가 1729처럼 변호받을 수 있을까요? 아니면 변호사도 두 손 드는 수가 어딘가에 있을까요?

직접 재 봅시다.




3. 첫 번째 부품, 이어서: 지루한 수 사냥 — 잣대 11개로 1,000개를 채점하다

‘흥미롭다’를 정확히 잴 수는 없지만, 흉내 낼 수는 있습니다. 수학에서 사랑받는 유명한 특징 11가지로 잣대 목록을 만들어 보겠습니다.

  • 소수 — 1과 자기 자신으로만 나누어지는 수 (2, 3, 5, 7, …)
  • 제곱수 — 같은 수를 두 번 곱해 만든 수 (1, 4, 9, 16, …)
  • 세제곱수 — 같은 수를 세 번 곱해 만든 수 (1, 8, 27, …)
  • 삼각수 — 1, 1+2, 1+2+3, … 처럼 차곡차곡 더해 만든 수 (1, 3, 6, 10, …)
  • 피보나치 — 앞의 두 수를 더해 다음 수를 만드는 그 유명한 수열 (1, 2, 3, 5, 8, …)
  • 팩토리얼 — 1×2, 1×2×3, … 처럼 차례로 곱해 만든 수 (1, 2, 6, 24, 120, …)
  • 2의 거듭제곱 — 2를 거듭 곱한 수 (1, 2, 4, 8, 16, …)
  • 회문수 — 거꾸로 읽어도 똑같은 수 (1~9, 11, 22, …, 121, …)
  • 완전수 — 자신을 뺀 약수를 모두 더하면 자기 자신이 되는 수 (6, 28, 496)
  • 고합성수 — 약수 개수의 역대 신기록 보유자 (1, 2, 4, 6, 12, 24, …)
  • 카탈랑 수 — 조합 문제마다 단골로 튀어나오는 수열 (1, 2, 5, 14, 42, …)

어떤 수가 이 가운데 몇 개의 잣대를 통과하는지를 그 수의 ‘흥미로움 점수’라고 부르기로 하고, 1부터 1,000까지 전부 채점해 보겠습니다. 과연 0점짜리 — 우리 잣대 기준의 ‘지루한 수’ — 가 나올까요?

파이썬 코드 보기 (펼치기 / 접기)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

# 한글 차트용 폰트 자동 등록(윈도우=맑은 고딕). 없으면 시스템 한글 폰트를 이름으로 탐색,
# 그래도 없으면 라벨을 영어로 폴백(두부 방지, OS 이식성).
_has_kr, KFONT = False, "DejaVu Sans"
for _fp in [r"C:\Windows\Fonts\malgun.ttf",
            "/System/Library/Fonts/AppleSDGothicNeo.ttc",
            "/usr/share/fonts/truetype/nanum/NanumGothic.ttf",
            "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
            "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc"]:
    try:
        fm.fontManager.addfont(_fp)
        KFONT = fm.FontProperties(fname=_fp).get_name()
        _has_kr = True
        break
    except Exception:
        continue
if not _has_kr:
    _avail = {f.name for f in fm.fontManager.ttflist}
    for _n in ["Malgun Gothic", "AppleGothic", "Apple SD Gothic Neo", "NanumGothic",
               "Noto Sans CJK KR", "Noto Sans KR", "Source Han Sans KR", "UnDotum"]:
        if _n in _avail:
            KFONT, _has_kr = _n, True
            break
if _has_kr:
    plt.rcParams["font.family"] = KFONT
plt.rcParams["axes.unicode_minus"] = False

def L(ko, en):
    return ko if _has_kr else en

DARK, LIGHT = "#0d1117", "#e6edf3"
BLUE, ORANGE, YELLOW, GREY, RED, GREEN = "#5dade2", "#e08a3c", "#f1c40f", "#7d8590", "#e74c3c", "#2ecc71"

# 잣대 11개로 1~1,000의 '흥미로움 점수'를 매기고, 첫 번째 0점짜리 수를 찾는다
N = 1000

sieve = np.ones(N + 1, dtype=bool)
sieve[:2] = False
for k in range(2, int(N ** 0.5) + 1):
    if sieve[k]:
        sieve[k * k::k] = False
primes = {int(n) for n in np.flatnonzero(sieve)}

squares = {k * k for k in range(1, N) if k * k <= N}
cubes = {k ** 3 for k in range(1, N) if k ** 3 <= N}
tri = {k * (k + 1) // 2 for k in range(1, N) if k * (k + 1) // 2 <= N}

fib, (a, b) = set(), (1, 2)
while a <= N:
    fib.add(a)
    a, b = b, a + b

fact, (f, k) = set(), (1, 1)
while f <= N:
    fact.add(f)
    k += 1
    f *= k

pow2 = {2 ** k for k in range(20) if 2 ** k <= N}
palin = {n for n in range(1, N + 1) if str(n) == str(n)[::-1]}
perfect = {n for n in range(2, N + 1)
           if sum(d for d in range(1, n) if n % d == 0) == n}

ndiv = np.zeros(N + 1, dtype=int)            # 고합성수: 약수 개수의 신기록 보유자
for d in range(1, N + 1):
    ndiv[d::d] += 1
hc, best = set(), 0
for n in range(1, N + 1):
    if ndiv[n] > best:
        hc.add(n)
        best = int(ndiv[n])

catalan, (c, k) = set(), (1, 0)
while c <= N:
    catalan.add(c)
    c = c * 2 * (2 * k + 1) // (k + 2)
    k += 1

BATTERY = [("소수", primes), ("제곱수", squares), ("세제곱수", cubes),
           ("삼각수", tri), ("피보나치 수", fib), ("팩토리얼", fact),
           ("2의 거듭제곱", pow2), ("회문수", palin), ("완전수", perfect),
           ("고합성수", hc), ("카탈랑 수", catalan)]

score = np.array([sum(n in s for _, s in BATTERY) for n in range(N + 1)])
zeros = [n for n in range(1, N + 1) if score[n] == 0]
first_boring = zeros[0]

print("우리 잣대 11개:", ", ".join(name for name, _ in BATTERY))
print(f"\n1~{N:,} 채점 결과:")
for v in range(int(score[1:].max()) + 1):
    cnt = int((score[1:] == v).sum())
    if cnt:
        print(f"  {v}점: {cnt:>3}개 ({cnt / N:.1%})")
print(f"\n가장 작은 0점짜리 수 = {first_boring}")
print(f"→ 축하합니다, {first_boring}. 방금 '가장 작은 지루한 수'가 되면서 그림의 주인공이 되었습니다.")

fig = plt.figure(figsize=(13, 5.6))
fig.patch.set_facecolor(DARK)
gs = fig.add_gridspec(1, 2, width_ratios=[2.6, 1.0], wspace=0.18,
                      left=0.055, right=0.975, top=0.82, bottom=0.13)

# (왼쪽) 수직선 위의 흥미로움 점수
ax = fig.add_subplot(gs[0, 0])
ax.set_facecolor(DARK)
rng = np.random.default_rng(42)
ns = np.arange(1, N + 1)
ys = score[1:] + rng.uniform(-0.13, 0.13, N)
m0 = score[1:] == 0
m1 = (score[1:] >= 1) & (score[1:] <= 2)
m3 = score[1:] >= 3
ax.scatter(ns[m0], ys[m0], s=10, color="#3a414a", lw=0)
ax.scatter(ns[m1], ys[m1], s=12, color=BLUE, alpha=0.75, lw=0)
ax.scatter(ns[m3], ys[m3], s=34, color=YELLOW, lw=0, zorder=4)
ax.scatter([first_boring], [ys[first_boring - 1]], s=240, facecolors="none",
           edgecolors=RED, lw=2.2, zorder=6)
ax.annotate(L(f"가장 작은 0점 = {first_boring}\n(이 순간 흥미로워짐)",
              f"smallest zero-scorer = {first_boring}\n(instantly interesting)"),
            xy=(first_boring, ys[first_boring - 1]), xytext=(175, 3.85),
            color=RED, fontsize=12.5, fontweight="bold",
            arrowprops=dict(arrowstyle="->", color=RED, lw=1.4))
for n in [int(v) for v in ns[score[1:] >= 5]]:        # 5점 이상의 유명인사들
    ax.annotate(f"{n} ({score[n]}{L('점', ' pts')})", xy=(n, score[n]),
                xytext=(n + 16, score[n] + 0.22), color=YELLOW, fontsize=11)
ax.set_xlabel(L("수 (1~1,000)", "n (1–1,000)"), color=LIGHT, fontsize=11.5)
ax.set_ylabel(L("흥미로움 점수 (통과한 잣대 개수)", "interestingness score"),
              color=LIGHT, fontsize=11.5)
ax.set_yticks(range(0, int(score.max()) + 1))
ax.set_title(L("대부분의 수는 어떤 잣대도 통과하지 못합니다", "Most numbers pass no test at all"),
             color=LIGHT, fontsize=12.5, pad=10)

# (오른쪽) 점수 분포: 지루함이 기본값
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_facecolor(DARK)
vals = range(int(score[1:].max()) + 1)
cnts = [int((score[1:] == v).sum()) for v in vals]
cols = ["#3a414a" if v == 0 else (BLUE if v <= 2 else YELLOW) for v in vals]
ax2.bar(vals, cnts, color=cols, width=0.72)
for v, c in zip(vals, cnts):
    if c:
        ax2.annotate(f"{c}", xy=(v, c), xytext=(v, c * 1.25), ha="center",
                     color=LIGHT, fontsize=10)
ax2.set_yscale("log")
ax2.set_ylim(0.7, 2300)
ax2.set_xticks(list(vals))
ax2.set_xlabel(L("점수", "score"), color=LIGHT, fontsize=11.5)
ax2.set_ylabel(L("수의 개수 (로그 눈금)", "count (log scale)"), color=LIGHT, fontsize=11.5)
ax2.set_title(L("지루함이 기본값", "Boring is the default"), color=LIGHT,
              fontsize=12.5, pad=10)

for a_ in (ax, ax2):
    for sp in a_.spines.values():
        sp.set_color("#3a414a")
    a_.tick_params(colors=GREY, which="both")

fig.suptitle(L("잣대 11개로 잰 1~1,000의 '흥미로움 점수' — 그리고 첫 번째 0점의 운명",
               "Interestingness scores of 1–1,000 under 11 tests — and the first zero"),
             color=LIGHT, fontsize=15.5, fontweight="bold", y=0.95)
plt.show()
우리 잣대 11개: 소수, 제곱수, 세제곱수, 삼각수, 피보나치 수, 팩토리얼, 2의 거듭제곱, 회문수, 완전수, 고합성수, 카탈랑 수

1~1,000 채점 결과:
  0점: 660개 (66.0%)
  1점: 290개 (29.0%)
  2점:  39개 (3.9%)
  3점:   4개 (0.4%)
  4점:   4개 (0.4%)
  5점:   1개 (0.1%)
  7점:   1개 (0.1%)
  9점:   1개 (0.1%)

가장 작은 0점짜리 수 = 18
→ 축하합니다, 18. 방금 '가장 작은 지루한 수'가 되면서 그림의 주인공이 되었습니다.

두 부분으로 된 그림. 왼쪽 산점도는 1부터 1,000까지 각 수가 잣대 11개 중 몇 개를 통과했는지를 점으로 찍은 것으로, 66%인 660개가 0점에 깔려 있고 9점의 1, 7점의 2, 5점의 6이 노란 점으로 두드러지며, 가장 작은 0점인 18이 빨간 동그라미와 ‘이 순간 흥미로워짐’ 주석으로 강조되어 있다. 오른쪽 로그 눈금 막대그래프는 0점 660개부터 9점 1개까지 점수가 높을수록 수가 급격히 줄어드는 분포로, 지루함이 기본값임을 보여 준다.

채점표가 꽤 가혹합니다. 1,000개 가운데 660개, 그러니까 66%가 0점입니다. 1점이 290개, 2점부터는 가파르게 줄어서 3점 이상의 ‘유명인사’는 통틀어 11개뿐입니다. 만점왕은 수 1입니다. 제곱수이자 세제곱수이자 삼각수이자 피보나치 수이자 팩토리얼이자… 무려 9점입니다. 2가 7점으로 그 뒤를 잇고, 6은 삼각수·팩토리얼·회문수·완전수·고합성수를 동시에 만족하는 5점짜리입니다. 55처럼 “삼각수이면서 피보나치 수이면서 회문수"인 숨은 재주꾼(3점)도 있습니다.

그리고 대망의 첫 0점, 18. 소수도, 제곱수도, 삼각수도, 피보나치 수도 아니고… 열한 개의 잣대를 전부 빠져나간 첫 번째 수입니다. 세상에서 가장 지루한 수의 후보를 찾았습니다.

그런데 축배를 들기 전에, 벌써 두 가지가 수상합니다.

첫째, 18에게도 변호사를 붙여 보면 — 나옵니다. 18은 자기 자릿수 합의 정확히 두 배가 되는 유일한 자연수입니다: $18 = 2 \times (1 + 8)$. 다른 수로는 안 됩니다(한 자리 수는 두 배 하는 순간 자기 자신을 넘어가 버리고, 두 자리 수로 따져 보면 조건이 “일의 자리 = 8 × 십의 자리"가 되어 18 하나만 남으며, 세 자리부터는 자릿수 합을 두 배 해도 턱없이 모자랍니다). 그러니까 18이 0점을 받은 것은 18이 지루해서가 아니라 우리 잣대가 11개뿐이어서입니다. 잣대 목록을 바꾸면 채점 결과도 바뀝니다. ‘흥미롭다’의 정체가 목록에 따라 출렁인다는 첫 번째 신호입니다.

둘째가 더 고약합니다. 18은 방금 “이 글에서 가장 작은 0점"이라는 이유로 그림의 주인공이 되어, 빨간 동그라미와 전용 화살표까지 받았습니다. 지루하다고 손가락질당하는 순간 흥미로워진 것입니다. 농담처럼 들리시겠지만, 정확히 이 일이 현실에서 반복적으로 일어났습니다. 기록이 남은 사건만 셋을 보여 드리겠습니다.

사건 1 — 39의 운명 (1986). 영국의 수학 저술가 데이비드 웰스는 흥미로운 수들을 작은 수부터 차례로 모은 사전, “흥미롭고 신기한 수 사전(The Penguin Dictionary of Curious and Interesting Numbers)“을 펴냈습니다. 그런데 이 사전에는 39번 항목에 이렇게 적혀 있습니다. “이 수는 첫 번째 흥미롭지 않은 수로 보인다. 물론 바로 그 사실이 이 수를 특별히 흥미롭게 만든다. 흥미롭지 않다는 성질을 가진 가장 작은 수이기 때문이다.” 지루함의 대표로 지목되는 순간 사전에 등재되어 버린 것입니다. 후일담도 있습니다. 1997년 개정판에서는 그 타이틀이 51로 넘어갔다고 전해집니다. 39는 한 번 지목된 덕분에 더 이상 그 자리에 있을 수 없었던 것이지요.

사건 2 — 11630의 저주 (2009). 수학자들에게는 OEIS(온라인 정수열 사전)라는 거대한 도감이 있습니다. 닐 슬론이 1964년에 손으로 쓴 카드 묶음으로 시작해 1973년에 수열 2,372개짜리 책으로, 1996년부터는 웹사이트로 키워 온 데이터베이스로, 지금은 39만 개가 넘는 수열(2025년 말 기준)이 등록되어 있습니다. 덕분에 ‘흥미로움’의 제법 객관적인 대용 지표가 하나 생깁니다. 그 수가 몇 개의 수열에 등장하는가. 2009년 6월 12일, 수학자 너새니얼 존스턴은 당시 159,437개의 수열을 전부 뒤져서 “11630은 첫 번째 흥미롭지 않은 수"라는 글을 발표합니다. 11630이 단 하나의 수열에도 등장하지 않는 가장 작은 수였던 것입니다. 그다음에 벌어진 일은 예상하신 그대로입니다. 글이 화제가 되자 11630은 이런저런 수열에 등장하기 시작했고, 같은 해 11월에는 타이틀이 12407로 넘어갔습니다. 2013년에는 14228로, 2020년대 초의 집계로는 20,067로 — 이 저주받은 왕관은 쓰는 순간 박탈되면서 계속 옮겨 다니는 중입니다. (덧붙이자면 존스턴이 이런 ‘흥미롭지 않은 수들’을 모아 아예 새 수열로 OEIS에 제출해 보았는데, 등재가 거절되었다는 후일담까지 있습니다.)

사건 3 — 슬론의 간극 (2011). 그렇다면 OEIS 등장 횟수라는 지표는 수의 세계를 어떤 모습으로 그려 낼까요? 2011년 고브리, 들라에, 제닐 세 연구자가 1부터 10,000까지의 모든 수에 대해 “등장하는 수열의 개수"를 세어 점을 찍어 보았습니다. 수가 커질수록 등장 횟수가 줄어드는 내리막이야 예상대로였는데, 충격은 모양이었습니다. 점들이 매끈한 띠 하나가 아니라 위아래 두 개의 구름으로 갈라져 있고, 그 사이가 휑하니 비어 있었던 것입니다. 이 빈 띠에는 ‘슬론의 간극(Sloane’s Gap)‘이라는 이름이 붙었습니다. 위쪽 구름(조사 구간의 약 18%)은 소수(위 구름의 약 3분의 2), 제곱수, 소인수가 많은 수 같은 ‘셀럽’들의 동네였습니다. 흥미로운 것은 그 이유입니다. 수의 복잡도에 대한 이론으로 구름 전체의 내리막 모양은 설명이 되는데, 간극만은 설명이 안 됩니다. 무작위로 만든 가짜 데이터베이스에서는 간극이 생기지 않거든요. 연구진이 지목한 남은 용의자는 수학 그 자체가 아니라 사람이었습니다. 수학자들이 일부 수를 더 많이 연구하니까, 그 수들이 더 많이 등장하고, 그래서 더 유명해지고, 그래서 더 연구되는 되먹임이 구름을 두 동강 낸다는 것입니다. 같은 데이터의 한 장면이 이 아이러니를 잘 보여 줍니다. 2009년 집계에서 전설의 주인공 1729는 380개의 수열에 등장했는데, 아무 일화도 없는 이웃 1728은 622개의 수열에 등장했습니다($1728 = 12^3$ 이라 조합 문제의 단골이거든요). 흥미로움이란 잰다고 가만히 있는 잣대가 아니라, 재는 사람들 때문에 움직이는 잣대였던 것입니다.

첫 번째 부품의 판정을 내리겠습니다. ‘흥미롭다’는 수에 새겨진 고정된 속성이라기보다, 수와 사람 사이에서 일어나는 사건에 가깝습니다. 일단 “수상함"으로 보류해 두고, 두 번째 부품으로 넘어갑니다.




4. 두 번째 부품: 막내는 반드시 있다 — 그리고 도미노

두 번째 부품은 “자연수의 줄에는 반드시 맨 앞이 있다"였습니다. 결론부터 말씀드리면 이 부품은 정품입니다. 수학에서는 정렬 원리(well-ordering principle) 라고 부릅니다. 자연수를 모아 놓은 묶음은, 비어 있지만 않다면, 반드시 가장 작은 원소를 갖는다는 원리입니다.

너무 당연해서 원리라고 부르기 민망할 정도지만, 사실 이 성질은 자연수의 세계가 누리는 특권입니다. 옆 동네인 ‘0보다 큰 분수의 세계’만 가도 무너지거든요. 가장 작은 양의 분수를 찾아보세요. 1/2? 그보다 작은 1/4이 있습니다. 1/100? 1/200이 있습니다. 어떤 후보를 잡아도 그 절반이 항상 더 작기 때문에, 그 세계에는 막내가 없습니다. 자연수의 세계는 다릅니다. 바닥이 1로 막혀 있고 수들이 띄엄띄엄 서 있어서, 어떤 묶음을 골라도 아래로 무한히 내려가는 일이 불가능합니다. 그래서 막내가 반드시 있습니다. 두 번째 부품은 의심의 여지 없이 합격 — 증명의 엔진 자체는 정품이라는 뜻입니다.

엔진이 정품이라면, 이제 증명이 실제로 일하는 모습을 구경해 봅시다. 3장의 잣대 11개를 1부터 50까지에 적용하면 0점짜리 ‘지루한 수’가 10개 나옵니다. 역설의 논리를 그대로 기계로 만들어서, 매 라운드 “지금 가장 작은 지루한 수"에게 타이틀을 수여하고 흥미로움으로 승격시키면 무슨 일이 벌어질까요?

파이썬 코드 보기 (펼치기 / 접기)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

# 한글 차트용 폰트 자동 등록(윈도우=맑은 고딕). 없으면 시스템 한글 폰트를 이름으로 탐색,
# 그래도 없으면 라벨을 영어로 폴백(두부 방지, OS 이식성).
_has_kr, KFONT = False, "DejaVu Sans"
for _fp in [r"C:\Windows\Fonts\malgun.ttf",
            "/System/Library/Fonts/AppleSDGothicNeo.ttc",
            "/usr/share/fonts/truetype/nanum/NanumGothic.ttf",
            "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
            "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc"]:
    try:
        fm.fontManager.addfont(_fp)
        KFONT = fm.FontProperties(fname=_fp).get_name()
        _has_kr = True
        break
    except Exception:
        continue
if not _has_kr:
    _avail = {f.name for f in fm.fontManager.ttflist}
    for _n in ["Malgun Gothic", "AppleGothic", "Apple SD Gothic Neo", "NanumGothic",
               "Noto Sans CJK KR", "Noto Sans KR", "Source Han Sans KR", "UnDotum"]:
        if _n in _avail:
            KFONT, _has_kr = _n, True
            break
if _has_kr:
    plt.rcParams["font.family"] = KFONT
plt.rcParams["axes.unicode_minus"] = False

def L(ko, en):
    return ko if _has_kr else en

DARK, LIGHT = "#0d1117", "#e6edf3"
BLUE, ORANGE, YELLOW, GREY, RED, GREEN = "#5dade2", "#e08a3c", "#f1c40f", "#7d8590", "#e74c3c", "#2ecc71"

# 역설의 논리를 그대로 실행: '가장 작은 지루한 수'를 한 라운드에 하나씩 승격시키는 도미노
import matplotlib.patches as mpatches
from matplotlib.patches import Rectangle

M = 50

sieve = np.ones(M + 1, dtype=bool)
sieve[:2] = False
for k in range(2, int(M ** 0.5) + 1):
    if sieve[k]:
        sieve[k * k::k] = False
primes = {int(n) for n in np.flatnonzero(sieve)}

squares = {k * k for k in range(1, M) if k * k <= M}
cubes = {k ** 3 for k in range(1, M) if k ** 3 <= M}
tri = {k * (k + 1) // 2 for k in range(1, M) if k * (k + 1) // 2 <= M}

fib, (a, b) = set(), (1, 2)
while a <= M:
    fib.add(a)
    a, b = b, a + b

fact, (f, k) = set(), (1, 1)
while f <= M:
    fact.add(f)
    k += 1
    f *= k

pow2 = {2 ** k for k in range(10) if 2 ** k <= M}
palin = {n for n in range(1, M + 1) if str(n) == str(n)[::-1]}
perfect = {n for n in range(2, M + 1)
           if sum(d for d in range(1, n) if n % d == 0) == n}

ndiv = np.zeros(M + 1, dtype=int)
for d in range(1, M + 1):
    ndiv[d::d] += 1
hc, best = set(), 0
for n in range(1, M + 1):
    if ndiv[n] > best:
        hc.add(n)
        best = int(ndiv[n])

catalan, (c, k) = set(), (1, 0)
while c <= M:
    catalan.add(c)
    c = c * 2 * (2 * k + 1) // (k + 2)
    k += 1

BATTERY = [primes, squares, cubes, tri, fib, fact, pow2, palin, perfect, hc, catalan]
born_interesting = {n for n in range(1, M + 1) if any(n in s for s in BATTERY)}
boring0 = [n for n in range(1, M + 1) if n not in born_interesting]
print(f"1~{M}에서 우리 잣대(11개)로 0점인 '지루한 수' {len(boring0)}개: {boring0}\n")

# 0 = 아직 지루함, 1 = 원래 흥미로움(잣대 통과), 2 = '타이틀'로 승격됨
state = np.zeros(M + 1, dtype=int)
state[list(born_interesting)] = 1
rows, promoted = [state[1:].copy()], []
r = 0
while (state[1:] == 0).any():
    r += 1
    m = min(n for n in range(1, M + 1) if state[n] == 0)
    print(f"{r:>2}라운드: 지금 가장 작은 지루한 수 = {m} → "
          f"'가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격")
    state[m] = 2
    promoted.append(m)
    rows.append(state[1:].copy())
print(f"\n종료: 지루한 수 0개. '증명' 완료 — ...정말일까요?")

grid = np.array(rows)                     # (라운드 + 1) x 50
R = grid.shape[0]

fig, ax = plt.subplots(figsize=(13, 5.2))
fig.patch.set_facecolor(DARK)
ax.set_facecolor(DARK)

PAL = {0: "#30363d", 1: "#33536e", 2: "#f1c40f"}
rgb = np.array([[tuple(int(PAL[v][i:i + 2], 16) / 255 for i in (1, 3, 5))
                 for v in row] for row in grid])
ax.imshow(rgb, aspect="auto", interpolation="nearest",
          extent=(0.5, M + 0.5, R - 0.5, -0.5))

# 셀 경계선 + 이번 라운드에 승격된 칸 강조(빨간 테두리와 숫자)
for x in np.arange(0.5, M + 1, 1):
    ax.plot([x, x], [-0.5, R - 0.5], color=DARK, lw=0.7)
for y in np.arange(-0.5, R, 1):
    ax.plot([0.5, M + 0.5], [y, y], color=DARK, lw=0.7)
for r_, m in enumerate(promoted, start=1):
    ax.add_patch(Rectangle((m - 0.5, r_ - 0.5), 1, 1, fill=False,
                           edgecolor=RED, lw=1.8, zorder=5))
    ax.annotate(str(m), xy=(m, r_), ha="center", va="center",
                color=DARK, fontsize=7.5, fontweight="bold", zorder=6)

ax.set_yticks(range(R))
ax.set_yticklabels([L("시작", "start")] +
                   [L(f"{i}라운드", f"round {i}") for i in range(1, R)],
                   color=LIGHT, fontsize=10)
ax.set_xticks([1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50])
ax.tick_params(colors=GREY)
ax.set_xlabel(L("수 (1~50)", "n (1–50)"), color=LIGHT, fontsize=11.5)
for sp in ax.spines.values():
    sp.set_color("#3a414a")

handles = [mpatches.Patch(color=PAL[1], label=L("원래 흥미로움 (잣대 통과)", "interesting by the tests")),
           mpatches.Patch(color=PAL[0], label=L("아직 지루함", "still boring")),
           mpatches.Patch(color=PAL[2], label=L("'가장 작은 지루한 수' 타이틀로 승격", "promoted by the title"))]
leg = ax.legend(handles=handles, loc="upper center", bbox_to_anchor=(0.5, -0.13),
                ncol=3, frameon=False, fontsize=10.5)
for t in leg.get_texts():
    t.set_color(LIGHT)

fig.suptitle(L("도미노 멸종 — '가장 작은 지루한 수'는 그 타이틀 때문에 살아남지 못합니다",
               "Domino extinction — the smallest boring number never survives its own title"),
             color=LIGHT, fontsize=15, fontweight="bold", y=0.97)
fig.subplots_adjust(left=0.075, right=0.985, top=0.88, bottom=0.2)
plt.show()
1~50에서 우리 잣대(11개)로 0점인 '지루한 수' 10개: [18, 20, 26, 30, 35, 38, 39, 40, 46, 50]

 1라운드: 지금 가장 작은 지루한 수 = 18 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 2라운드: 지금 가장 작은 지루한 수 = 20 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 3라운드: 지금 가장 작은 지루한 수 = 26 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 4라운드: 지금 가장 작은 지루한 수 = 30 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 5라운드: 지금 가장 작은 지루한 수 = 35 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 6라운드: 지금 가장 작은 지루한 수 = 38 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 7라운드: 지금 가장 작은 지루한 수 = 39 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 8라운드: 지금 가장 작은 지루한 수 = 40 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
 9라운드: 지금 가장 작은 지루한 수 = 46 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격
10라운드: 지금 가장 작은 지루한 수 = 50 → '가장 작은 지루한 수'라는 희귀한 타이틀 획득 → 흥미로움으로 승격

종료: 지루한 수 0개. '증명' 완료 — ...정말일까요?

1부터 50까지의 수를 가로축에, 시작부터 10라운드까지를 세로축에 둔 격자 그림. 잣대를 통과해 원래 흥미로운 파란 칸들 사이에 지루한 수 10개(18, 20, 26, 30, 35, 38, 39, 40, 46, 50)가 어두운 세로줄로 남아 있다가, 매 라운드 가장 작은 지루한 수가 ‘가장 작은 지루한 수’ 타이틀을 받아 노란 칸으로 승격되며 왼쪽부터 차례로 사라져, 10라운드 만에 지루한 수가 전부 멸종하는 도미노 과정을 보여 준다.

1라운드에서 18이 — 3장에서 본 그대로 — 왕관을 쓰고 승격됩니다. 그러면 “가장 작은 지루한 수” 자리는 20에게 넘어가고, 2라운드에서 20도 같은 논리로 승격됩니다. 26, 30, 35, 38이 차례로 사라지고, 7라운드에는 웰스 사전의 그 39가 정확히 같은 운명을 맞습니다. 그렇게 딱 10라운드 만에 지루한 수는 멸종합니다. 시작 목록이 무엇이었든 결과는 같습니다. 매번 줄의 맨 앞이 잘려 나가니, 지루한 수의 줄은 반드시 앞에서부터 통째로 사라질 수밖에 없습니다.

그런데 이 그림을 가만히 들여다보면 속임수의 꼬리가 보이기 시작합니다. 색을 보세요. 파란 칸은 잣대 11개 중 무언가를 통과해서 흥미로워진 수입니다. 반면 노란 칸은 잣대를 단 하나도 통과하지 못한 채, “타이틀"이라는 전혀 다른 종류의 이유로 흥미로워진 수입니다. 그리고 그 타이틀(“가장 작은 지루한 수”)이 가리키는 대상은 한 라운드가 지날 때마다 바뀝니다. 18이 왕관을 쓴 근거는 1라운드가 끝나는 순간 이미 소멸했습니다. 2라운드의 세계에서 “가장 작은 지루한 수"는 18이 아니라 20이니까요.

엄밀히 말하면 베켄바흐의 원래 증명은 이런 도미노가 아니라 “막내 $m$ 이 있다, $m$ 은 흥미롭다, 모순"으로 한 방에 끝나는 귀류법입니다. 하지만 일부러 도미노 버전으로 풀어 그려 본 이유가 있습니다. 한 방짜리 귀류법에서는 트릭이 어디서 작동하는지 보이지 않지만, 라운드를 거듭하는 도미노에서는 매 라운드 게임의 규칙이 바뀌고 있다는 사실이 색깔로 드러나기 때문입니다. 범인의 윤곽이 잡혔습니다. 검거하러 갑시다.




5. 범인 검거: 움직이는 골대

부품 검사 결과를 모아 봅시다. 두 번째 부품(정렬 원리)은 정품이었습니다. 세 번째 부품(“가장 작은 지루한 수라는 타이틀은 흥미롭다”)도 심정적으로는 인정할 만합니다. 그렇다면 남는 것은 첫 번째 부품, ‘흥미롭다’ 그 자체입니다. 그리고 범인은 실제로 여기에 숨어 있습니다.

정렬 원리는 아무 모임에나 들이댈 수 있는 만능 도구가 아닙니다. 어떤 수가 속하는지 아닌지가 똑 떨어지게 정해지는 모임에만 적용할 수 있습니다. “100보다 작은 짝수들"은 그런 모임입니다. 어떤 수를 들이밀어도 소속 여부가 다툼의 여지 없이 판정되니까요. 그런데 “지루한 수들"은 어떤가요? 18은 지루한가요? 우리 잣대 11개로는 지루하고, $18 = 2 \times (1+8)$ 잣대를 추가하면 흥미롭고, 이 글을 여기까지 읽으신 분에게는 이미 흥미로운 수입니다. 소속이 사람과 시점에 따라 출렁이는 이런 모임은 수학적인 의미의 집합이 아니고, 따라서 정렬 원리를 적용할 대상 자체가 애초에 없었습니다. 증명은 2단계에서 이미 시작조차 못 하고 있었던 것입니다.

그런데도 증명이 그럴듯해 보였던 이유는 4단계의 바꿔치기에 있습니다. 증명은 1~3단계에서 ‘흥미롭다’를 마치 고정된 잣대 목록처럼 다룹니다. 그래 놓고 결정적인 4단계에서 “가장 작은 지루한 수라는 타이틀” — 그 목록에는 없던, 목록 전체를 밖에서 내려다봐야만 생겨나는 새 잣대 — 를 슬쩍 추가합니다. 골대를 옮겨 놓고 골인을 선언한 셈입니다. 철학자 콰인의 분류를 빌리면 이런 부류는 허위 역설(falsidical paradox), 즉 결론도 틀렸고 증명에도 오류가 있지만 그 오류가 교묘해서 곱씹을 가치가 있는 역설에 해당합니다.

이 진단이 맞는지는 사고 실험 두 개로 확인할 수 있습니다.

실험 1 — 정의를 못박으면 역설은 증발합니다. ‘흥미롭다 = 우리 잣대 11개 중 하나라도 통과’라고 박아 두면 어떻게 될까요? 그러면 “가장 작은 지루한 수"는… 그냥 18입니다. 모순도 폭발도 없습니다. 18이 이 글에서 유명해진 것은 잣대 목록 밖의 일이고, 목록 기준 0점이라는 사실은 조금도 변하지 않으니까요. 고정된 정의는 자기 자신을 삼킬 수 없고, 자기 자신을 삼킬 수 없는 정의에서는 모순이 만들어지지 않습니다.

실험 2 — 정의가 자기 자신을 삼키게 만들면 진짜 폭탄이 됩니다. 반대로 ‘흥미롭다’를 “짧은 말로 콕 집어 묘사할 수 있다"처럼 정확하게 다듬어 봅시다. 그러면 “스무 글자로 설명할 수 없는 가장 작은 수"라는 문구를 만들 수 있는데 — 띄어쓰기를 빼고 한 글자씩 세어 보세요. 이 문구는 고작 열여섯 글자입니다. 설명할 수 없는 수를 방금 열여섯 글자로 설명해 버린 것이지요. 이것이 바로 베리의 역설이고, 거기서부터는 웃자고 하는 이야기가 아니라 괴델과 튜링까지 이어지는 수리논리학의 진짜 사건이 됩니다(그 이야기는 베리의 역설 글에서 따로 다뤘습니다). 말하자면 흥미로운 수 역설은 베리의 역설의 순한맛입니다. ‘흥미롭다’가 애매한 덕분에 모두가 웃고 넘어갈 수 있지만, 그 애매함을 걷어 내는 순간 같은 자리에서 진짜 폭탄이 나옵니다.

그리고 3장의 OEIS 이야기가 마지막 교훈 하나를 보탭니다. ‘흥미로움’을 객관적인 지표로 바꿔치기해도 — 이를테면 “등장하는 수열의 개수"로 — 그 지표가 사람들의 관심으로 만들어지는 한 문제는 사라지지 않습니다. 재는 행위가 잰 값을 바꾸니까요. 11630은 “어디에도 안 나오는 수"로 지목되는 순간 여기저기 나오는 수가 되었습니다. 흥미로움은, 측정하면 변하는 양입니다.




6. 대단원의 막: 그래도, 모든 수는 흥미롭습니다

정리는 무너졌습니다. “모든 수는 흥미롭다"는 수학의 정리가 아니라 교묘하게 포장된 농담이었고, 범인은 ‘흥미롭다’라는 움직이는 골대였습니다. 그런데 이 농담이 팔십 년 가까이 사랑받아 온 데에는 이유가 있다고 생각합니다. 결론이 — 정리로서는 가짜인데 — 태도로서는 진짜이기 때문입니다.

라마누잔이 서른두 살에 세상을 떠난 이듬해, 하디는 추도문에 이런 문장을 남겼습니다.

모든 양의 정수는 그의 개인적인 친구였다 — 라고 말한 것은, 내 기억이 맞는다면, 리틀우드 씨였다.

이 명언에는 귀여운 후일담이 있습니다. 리틀우드의 회고에 따르면 하디의 초고에는 “누군가 말했듯이"라고만 적혀 있었답니다. 교정쇄를 읽던 리틀우드는 “누가 한 말이지? 내가 했더라면 좋았을걸” 하고 생각했는데, 다음 교정쇄에서는 그 말의 주인이 리틀우드로 바뀌어 있었다고 합니다. 명언의 소유권마저 ‘가장 작은 지루한 수’의 왕관처럼 슬그머니 자리를 옮겨 다닌 셈입니다.

사족을 하나만 보태겠습니다. 하디가 시시하다고 했던 그 수는, 백 년이 지난 지금 픽션 속 이스터에그로 살고 있습니다. 작가진에 수학 박사까지 둔 애니메이션 〈퓨처라마〉는 로봇 벤더를 ‘1729번째 아들’로 부르고, 우주선 님버스호에 선체번호 BP-1729를 달고, 평행우주 1729호를 등장시켰습니다. 수학 저술가 사이먼 싱이 2013년 BBC에 “왜 1729가 퓨처라마 곳곳에 숨어 있는가"라는 글을 따로 썼을 정도입니다. 극장판에는 한술 더 떠 번호가 87539319인 택시가 지나가는데 — 두 세제곱수의 합으로 ‘세 가지’ 방법으로 쓸 수 있는 가장 작은 수입니다. 라마누잔의 택시는 픽션 속에서 아직도 달리는 중입니다.

“모든 수는 흥미롭다"를 증명할 수는 없습니다. 하지만 “지루해 보이는 수는 아직 변호사를 만나지 못했을 뿐"이라는 쪽에 거는 것은, 적어도 지금까지의 전적을 보면 꽤 안전한 베팅입니다. 39가 그랬고, 11630이 그랬고, 우리의 18이 그랬으니까요.

다음에 택시를 타시면 번호판을 한번 봐 주세요. 처음에는 분명 심심한 수로 보일 겁니다. 하디에게도 그랬으니까요. 하지만 “넌 뭐가 특별하니"라고 묻기 시작하는 순간, 이 역설이 우리에게 허락한 단 하나의 확실한 결론이 작동하기 시작합니다.

지루한 수는, 우리가 들여다보는 동안에는, 존재할 수 없습니다.