Shifeng Chen (陈诗峰) & Paul JL Wu agentic-portfolio English 中文 Español 한국어✉️ 無料メーリングリスト
← ポートフォリオに戻る

AI-NATIVEシリーズ · 四つの年齢でたどる数 · 第4話(最終話)· 20歳

数と表現──すべてのプログラマが最初に出会う抽象化(20歳編)

執筆:Shifeng Chen (陈诗峰) & Paul JL Wu · agentic-portfolio-lovat.vercel.app · 2026-10-15 · 読了時間14分程度

Cover: Number vs representation, the first abstraction every programmer uses, for age 20. Three cards: who it is for (20-year-olds who write code or will soon), what you leave with (a test for which layer a fact belongs to, and a round-trip converter), the one finding (positional notation is a log-length code with a fixed alphabet). Series strip with episode 4 highlighted.
四つの年齢でたどる数・第4話(最終話):20歳編。

1分でつかむ要点

このエッセイについて 20歳前後のエンジニアに向けたエッセイ。子どもがリンゴや石で出会う「数はその名前ではない」という発想は、抽象データ型・エンコーディング・浮動小数点・Unicode数字の根底にある同じ抽象化だ。

なぜこれが大事なのか バグは「値」と「エンコーディング」の間のすき間に潜む。たとえば、0.1 + 0.2 が 0.3 にならない現象、同じバイト列が読む側によって 251 にも −5 にもなること、スプレッドシートの列がゼロのない26進数で表されていることなどが典型例だ。どの事実がどの層に属するかを見極めるのは、エンジニアの日常的な判断材料である。

このエピソードを読んだ後にできること すべての数を3種類のエンコーディングで往復変換し、不変性テストを通すコンバーターを書こう。自分のコードから表現依存のバグを一つ見つけ、さらに15歳の子に位取りの証明を教えてみてほしい。

Numbers at Four Ages — シリーズの背骨

▶ 動いているところを見る:ライブデモを開く 公開 · ログイン不要

  1. 7歳編 · 数ってなに? 第1話
  2. 11歳 · なぜ数字の書き方はこんなに多いのか? 第2話
  3. 15歳編 · 十個の記号ですべての数 第3話
  4. 20歳編:数と表現の違い この回

なぜ「数」とその表現の違いを、すべてのプログラマーが知っておくべきなのか?

このエピソード自体では位取りの証明は扱わない。それは第3話(15歳編)で取り上げる。連続量(数えるのではなく測るもの)は次のシーズンのテーマだ。

この回のテーマ:数と表現の違い

「数」と「表現の違い」について、エンジニアの視点から語るエッセイだ。値そのものと、それがどのように書かれたり保存されたりするかの違いに焦点を当てる。対象は、すでにコードを書くか、これから書く予定の20歳前後の読者。Pythonが動くノートPCと、演習に15分あれば十分だ。

全4話の最終回であり、ここでシリーズの円が一つつながる。

このエピソードでは、子どもの頃に出会う「数とその表し方の違い」という発想が、実はすべてのプログラマが最初に使う抽象化そのものであることを示す。ここで扱うアイデアは、章(本シリーズ共著者・陈诗峰(Shifeng Chen)による「数とその表現」)に基づいている。さらに一歩進めると、それは自分のコードで実際に動かせるテストになる。

このシリーズは、キッチンの一場面から始まり、卵の入ったボウル、レストラン、ファストフードの倉庫と、段階的にスケールアップしていく。そして最終地点は、全国規模の食品サプライチェーンだ。42カートン入りの箱が十数種類のシステムを通過する。バーコードはある方法でそれをエンコードし、倉庫のデータベースはバイナリ整数として保存し、CSVエクスポートは文字列"0042"を書き、スプレッドシートはAP列に記録する。数量自体は変わらないのに、システムごとに表し方が異なる。このギャップこそが、サプライチェーンのバグの温床となる。

この先を読む前に 最後には、15歳の子どもにエピソード3の一意性証明を説明することになる。つまり、誰かに説明するつもりで読んでほしい。39件の研究をまとめたところ、「教えるつもりで学習した」場合の成績はg = 0.48、一方「教えるつもりなし」で学習した場合はg = −0.02 (Kobayashi (2024), Educational Psychology Review (ERIC EJ1414484)).

アクティビティ1 · 片手で31まで数える(まず自分で考案)

指を1本立てるごとに1と数えるなら、片手で0から5まで数えられる。ここから先は読まずに、0から31までのすべての数に対して一意の指パターンができ、どれも重複しないような数え方を自分で考えてみてほしい。

その方法で19と31を表現し、考案したルールを書き出してみよう。

もし各指が前の指の2倍(1, 2, 4, 8, 16)を意味するなら、あなたは2進法を発明したことになる。19は16+2+1、31は5本すべての指。手も指の本数も同じまま、数えられる範囲は6倍になった。表現を変えただけで、数そのものは変わらない。これがこのエッセイの本質を、たった一つの動作で体現している。

「同じ数」とはペアを作ることで定義され、表現はエンコーディングである

エピソード1のリンゴ遊びは、単なる子ども向けの単純化ではない。「同じ数」の定義そのものであり、Fregeが算術の基礎を築いた根拠だ。数学の基礎論では、2つの集合が「同じ数」を持つのは、一対一対応 が存在する場合に限る。これはヒュームの原理であり、Fregeが1884年に算術を構築した根底にある(Zalta, Stanford Encyclopedia of Philosophy, "Frege's Theorem and Foundations for Arithmetic"(訳:「ザルタ、スタンフォード哲学百科事典『フレーゲの定理と算術の基礎』」))。この定義には数字という言葉は一切出てこない。

A 表現 とは、その値をエンコードしたもの、すなわち何らかのアルファベット上の有限な文字列と、それを読むためのルールの組み合わせだ。十進法、二進法、ローマ数字、棒線、レジスタ内のビット列、これらはすべて表現である。ソフトウェア工学でも同じ分離があり、「抽象データ型」は値が何をするかと、それがどう保存されるかを分けて考える。抽象データ型とは、値が持つ本質的なふるまいのことであり、保存方法とは切り離されている。この考え方は1974 (Liskov & Zilles (1974), "Programming with abstract data types", ACM SIGPLAN Noticesで示された。数は抽象データ型の元祖であり、あらゆる記数法はその具体的な実装の一つだ。

どのエンコーディングでも変わらず成り立つ性質は不変量と呼ばれる。エンコーディング固有の事実と不変量を見分ける力こそ、このエッセイで鍛えるスキルだ。今すぐNumber Playgroundで体験できる。任意の数を9通りに表現し、Chenのソートゲームも遊べる無料ページだ。

シリーズの根幹はこの一文に尽きる。「数は値、表現はエンコーディング、正しいコードは値だけに依存する」。

なぜ位取り記法が勝ったのか――固定されたアルファベットで対数長のコード

Chenの章は圧縮の歴史そのものであり、エンジニアならこう言い切れる。

Chenの言葉を借りれば「位取りは、無限の記号を無限の桁に変える」。

A log-scale bar chart of how many symbols it takes to write one million: tally marks 1,000,000; groups of five 200,000; Egyptian 1; base ten 7; base two 20; zero-free base ten 6. The base ten bar is orange. A note says Egyptian writes a million with one sign but has no sign above it.
100万を書くのに必要な記号数。位取り記法は、線形に増える長さを対数的な長さに変える。

ただし、その便利さには代償もある。空の桁も含めてすべての桁を保持する必要があり、それがプレースホルダーとしてのゼロの役割だ。もっとも、ゼロは厳密には必須ではない。全単射(ゼロなし)基数kでは、桁は1からkまでを使う。すべての正の整数には必ず一意の文字列が対応し、空文字列がゼロとなる。実はこれ、日常的に使っている。スプレッドシートの列AからZ、そしてAA、AB…は全単射な基数26の表記法だ。Excelでは16,384列まで使え、最後の列はXFDとなる(Microsoft, "Excel specifications and limits"(訳:Microsoft, Excelの仕様と制限)): 24 × 26² + 6 × 26 + 4 = 16,384.

アクティビティ2:コンバーターを書き、何が変わってはいけないかをテストせよ

以下のバージョンを読む前に、3種類のエンコーダとそのデコーダを書いてみよう。ゼロを使う基数b、ゼロなしの10進法(1〜9と10用のκ、Chenの記号)、そしてスプレッドシートの列ラベルだ。次にプロパティテストを書こう。すべてのエンコーディングが往復変換できること、そして特定の表現だけで成り立つ「事実」を検出できることを確認する必要がある。

下記のバージョンは、すべてのアサーションを満たす:

DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"
def to_base(n, b):
    if n == 0:
        return "0"
    out = ""
    while n:
        n, r = divmod(n, b)
        out = DIGITS[r] + out
    return out
def from_base(s, b):
    return int(s, b)
def to_zero_free_ten(n):            # digits 1-9 and κ (ten); no 0
    out = ""
    while n:
        r = n % 10 or 10
        out = "123456789κ"[r - 1] + out
        n = (n - r) // 10
    return out
def from_zero_free_ten(s):
    n = 0
    for ch in s:
        n = n * 10 + "123456789κ".index(ch) + 1
    return n
def column_label(n):                # spreadsheet columns: zero-free base 26
    out = ""
    while n:
        r = n % 26 or 26
        out = chr(64 + r) + out
        n = (n - r) // 26
    return out
def column_number(s):
    n = 0
    for ch in s:
        n = n * 26 + ord(ch) - 64
    return n
assert to_zero_free_ten(3020) == "2κ1κ" and to_zero_free_ten(10**6) == "99999κ"
assert column_label(27) == "AA" and column_label(16384) == "XFD"
for n in range(1, 10_000):          # every encoding round-trips: the value is untouched
    assert from_base(to_base(n, 3), 3) == n
    assert from_zero_free_ten(to_zero_free_ten(n)) == n
    assert column_number(column_label(n)) == n
    assert (n % 3 == 0) == to_base(n, 3).endswith("0")              # true in base 3 ...
assert any((n % 3 == 0) != str(n).endswith("0") for n in range(1, 100))  # ... false in base ten: a fact about notation

最後の2つのアサーションに注目してほしい。「3で割り切れるなら末尾の桁は0」は、基数3では常に成り立つが、最後の行では10進法で破綻している(3は3で割り切れるが末尾は3)。あるエンコーディングで成り立ち、別のエンコーディングで成り立たない性質は、数そのものではなく表現に属する。Chenの並べ替え実験(子どもが文が数についてか書き方についてかを判別する)は、値を固定してエンコーディングだけを変えるプロパティテストと同じ発想だ。基数bでは、桁和ショートカットはb − 1 (Weisstein, MathWorld, "Divisibility Tests"(訳:Weisstein, MathWorld,「割り算の判定法」)の約数に対して正確に機能する。つまり、3や9の判定法は10進法固有の事実であり、3進法の事実ではない。

同じビットでも数は違う——コードで現れる落とし穴

Pythonプロンプトで再現できる3つの例。それぞれ、表現の事実が値の層に漏れ込んでいる。

サプライチェーンの現場では、製品コード「0042」がスプレッドシートに読み込まれると数値の42に変換され、識別子だった先頭のゼロが消える。結果、どこかの倉庫が製品0042(ラバーダック)と製品42(これもラバーダック、別の仕入先)を同一視し、アヒルを2倍発注してしまう。もともとこのコードは数字列として保存された識別子であり、数量ではなかった。値がどの層に属するかを見極めていれば、こうした事故は防げた。

もう一つの視点:数に「身体」はあるのか?

このシリーズでは、Paul の「プレイ・エンジニアリング」ノートから着想を得たレンズを使う。仮説ではなく、実際に検証されたものだ。身体には spirit(精神)、bone(骨)、flesh(肉)、skin(皮膚)がある。数の体系に当てはめると:

A table titled The same map in code. Rows: spirit is the value forty-two, with the open question of whether it exists without code; bone is the type structure, one value in many types; flesh is parse, format and add with carry, which must be rewritten when the encoding changes; skin is the strings 42, 0042, 0x2A, 101010 and the spreadsheet column AP, new skin same value; two forms are int for counting and float for measuring, where 0.1 has no exact binary skin.
この構造はコードにもそのまま当てはまる。エンコーディングを変えても変わらず残るものが値であり、パースやフォーマット、繰り上がりの処理はエンコーディングごとに書き換えられる。

この構造を持つ意味は何か?エンコーディングを変えても変わらず残るものは値に属し、変化してしまうものは実装層に属する。 加算は spirit、繰り上がり規則は flesh だ。「N に達したら1繰り上げる」というN入りのルールなので、基数を変えればNだけが変わり、加算そのものは変わらない。コードでは「値層で性質をテストし、エンコーディング固有の事実はエンコーディングのインターフェースの裏に隠す」という設計になる。

この構造が通用しない場面もある:

  1. 骨(基数)を入れ替えても spirit(値)は保てるが、現実の身体でそんなことはできない。
  2. 「離散と連続」は層ではなく軸だ。アリストテレスはこう記している――量とは、離散的であるか連続的であるかのいずれかである。" (Aristotle, Categories, Part 6, tr. E. M. Edghill (MIT Internet Classics Archive))。ここで扱うのはすべて離散量であり、「測る」ことや、正しく扱うfloatは次のシーズンの話になる。
  3. 「精神」が独立に存在するかどうかは決着がついていない。プラトン主義では、数は実在し、抽象的で、いかなる心にも依存しない(Linnebo, Stanford Encyclopedia of Philosophy, "Platonism in the Philosophy of Mathematics")。一方、唯名論では、抽象的な「数」という対象自体が存在しない(Bueno, Stanford Encyclopedia of Philosophy, "Nominalism in the Philosophy of Mathematics")。エンジニアは不可知論で構わない――大事なのはインターフェースであり、それ自体が一つの哲学的立場(機能主義)だ。

なぜ一つの発想が四つの年齢を貫けるのか

このシリーズは、Jerome BrunerのThe Process of Education(1960年)にしばしば帰せられる「どんな主題も、知的に誠実な形ならどの発達段階でも教えられる」という主張に賭けている。ここではあえて意訳した。原文は未確認なので直接引用はしていない。

「誠実さ」の基準も同じく不変性テストだ。各エピソードは同じ核を持ち、7歳で学んだことは20歳になっても一つも学び直す必要がない。ペアリングゲームはヒュームの原理そのもの。「5はただの名前」が値とエンコーディングの分離。両手カウンターはキャリーの規則そのものだ。

シリーズの設計思想は、検証可能な研究に基づいている:

もうひとつ、私自身の視点を紹介する。私は「真・愛・美」は三つの別々の理想ではなく、一つの現実の三つの側面であり、私の信仰では一人の人格の現れだと考えている。このシリーズでは、信仰抜きでも通用するエンジニアリングのチェックリストとしても機能する。レッスンには「真」(学ぶ人が自分で確かめられること)、「愛」(特定の相手に向けて書かれ、その人のつまずきに寄り添うこと)、「美」(誰かに見せたくなる瞬間があること)が必要だ。

「半分だけ正しい」典型的な誤解

さあ、今度は人に説明してみよう

あなたの番だ。 15歳の子を見つけて、「証明:すべての数にはただ一つの綴りがある」(episode 3)を一緒にやってみよう。手順は書いてあげず、「352を3で割った余りは?」「その後、商はどうなる?」と問いかけ、誰も数字を選んでいないことに気づかせる。

目標: 15歳の子が自力で352の3進法での余りの手順(111001)を書き、なぜ最後の桁が必然なのかを一文で説明できる。その年齢と結果をこの記事のコメント欄に投稿しよう。

なぜ重要か――5回の「なぜ」

問題:データパイプラインが商品コードの先頭ゼロを落とし、0042と42が統合されて2つの商品が1つになった。

  1. なぜコードが統合されたのか? ローダーが「0042」を数値42として解釈した。その結果、両方の文字列が同じ値に結びつき、識別子が衝突した。
  2. なぜ数値として解釈されたのか? フィールドの意味ではなく、文字(数字のみ)の見た目から型が推測されたためだ。
  3. なぜ見た目から推測したのか? システムが「数字の並んだ文字列」という表現を、そのまま値として扱ってしまったからだ。これはまさにChenの章で子どもたちに避けさせている混同そのものだ。
  4. なぜ見逃されたのか? 値を固定したままエンコーディングだけを変えるテストがなかった。もしそのテストがあれば、コンバーターの十進法との比較行でbase-3の「事実」が十進法で破綻するように、すぐに問題が発覚したはずだ。
  5. 根本原因 コードが値そのものではなく、表現の層に依存していた。解決策はこのエピソードのルール通り:値(数量か識別子か)をまず決め、表現固有の事実はインターフェースの裏側に隠し(Liskov & Zilles (1974), "Programming with abstract data types", ACM SIGPLAN Notices)、エンコーディングをまたいで不変性をテストすることだ。

実践編:今週やること

  1. 「教えるつもりで読む」一文を読む。
  2. 片手で31まで数える(2分)。
  3. 3種類のコンバーターとプロパティテストを書き、上記のバージョンと見比べる(15分)。
  4. を開く。プレイグラウンド。16384と1000000を入力し、各行(スプレッドシートの列も含む:16384はXFD)で自作コンバーターと照合し、N-or-Rゲームを試す。
  5. 自分のコードの中で、事実が表現(文字列と数値、浮動小数点の等価性、数字のみパーサなど)に依存している箇所を一つ見つけ、不変性テストを一つ追加する。
  6. エピソード3の証明を15歳の子に教える。

フィードバック:できたかどうかの確認

1週間後にもう一度自分でチェックしよう。テストは再読よりも効果が高かった(1週間 (Roediger & Karpicke (2006), "Test-Enhanced Learning", Psychological Science 17)。ただし、締切直前のプレッシャー下でも習慣が続くかどうかまでは分からない。CI(継続的インテグレーション)でのプロパティテストだけが、それを自動で見張ってくれる。

実践のための決めごと(今ここで線を引く)

このエピソードの「真・愛・美」

5Sの自己採点

S主張根拠
シンプルこの文章は、高校3年生程度でも読みやすいレベルで書かれている。この文章のFlesch–Kincaidグレード:8.4(バンド ≤ 13)、再計算元:node scripts/check-numbers-four-ages.mjs
堅実定義や数値には出典があり、コードも実際に動作する。Excelの16,384列(Microsoft); ヒュームの原理
鋭さ位取り記数法は、固定された記号セットで表現長が対数的に伸びる符号化方式であり、正しいコードは値そのものだけに依存する。対数長 · そのプロパティテスト
SMART今週やること:コンバーター作成、自分のコードに不変性テストを1つ追加、誰かに一度教えてみる。実践 · プレイグラウンド
驚きあなたのスプレッドシートは、実はずっとゼロのない26進法で数えていた。XFD = 16,384
真・愛・美実行できる主張・教える相手・どの年齢にも通じる一つのアイデア。真・愛・美

出典

  1. 陈诗峰 (Shifeng Chen)、草稿章《第一章 数とその表現形式》("Numbers and Their Representations")、2026年。原著章(PDF・中国語)を読む本シリーズ共著者。
  2. Zalta, E. N. "Frege's Theorem and Foundations for Arithmetic."Stanford Encyclopedia of Philosophy. plato.stanford.edu
  3. Liskov, B. & Zilles, S. (1974). Programming with abstract data types.ACM SIGPLAN Notices. Crossref 10.1145/942572.807045
  4. Weisstein, E. W. "Digit." MathWorld.mathworld.wolfram.com
  5. Weisstein, E. W. "Divisibility Tests." MathWorld.mathworld.wolfram.com
  6. Microsoft. "Excel specifications and limits."support.microsoft.com
  7. Unicode Character Database, UnicodeData.txt.unicode.org
  8. Aristotle.Categories第6部、E. M. Edghill訳。classics.mit.edu
  9. Linnebo, Ø. "Platonism in the Philosophy of Mathematics."Stanford Encyclopedia of Philosophy. plato.stanford.edu
  10. Bueno, O. 「Nominalism in the Philosophy of Mathematics.」Stanford Encyclopedia of Philosophy. plato.stanford.edu
  11. Cowan, N. (2001). The magical number 4 in short-term memory. Behavioral and Brain Sciences 24. doi:10.1017/S0140525X01003922
  12. Kalyuga, S., Ayres, P., Chandler, P. & Sweller, J. (2003). The expertise reversal effect. Educational Psychologist 38. doi:10.1207/S15326985EP3801_4
  13. Kobayashi, K. (2024). Interactive learning effects of preparing to teach and teaching. Educational Psychology Review. ERIC EJ1414484
  14. Roediger, H. L. & Karpicke, J. D. (2006). Test-enhanced learning. Psychological Science 17. doi:10.1111/j.1467-9280.2006.01693.x
  15. DeLamater, M. (1999), on Bruner's hypothesis. Education Week. edweek.org(二次資料。一次資料の原文は未確認)

関連エピソード

執筆:Shifeng Chen(陈诗峰)&Paul JL Wu · agentic-portfolio · 2026-10-15。共著:陈诗峰(Shifeng Chen)の「Numbers and Their Representations」章より(元PDFは冒頭と出典欄にリンク)。 制作:playbook-math:一つの発想を四つの世代で、すべての数は検証済みの出典に基づく。ここで述べる内容は私個人の見解であり、所属組織のものではない。