Migdal

Cover image for 位取り記数法は「一番合理的な記数法」ではない。
Casolot
Casolot

Posted on

位取り記数法は「一番合理的な記数法」ではない。

位取り記数法は、過大評価されている

多くの人間は、記数法と言われたときには位取り記数法のことしか考えないか、少なくとも位取り記数法が、ローマ数字などの記数法から進化した最も先進的で合理的な記数法であると考えているように見えます。
人工言語を作られている方は記数法の議論をすっ飛ばして、とにかく「何進数を採用するか」だけに焦点を当てていないでしょうか?

しかし、本当に位取り記数法は合理的なんでしょうか。他の記数法は考えられないのでしょうか。
ここでは、位取り記数法が「万能」ではないことを示した上で、位取り記数法とは別の設計思想を持つ記数法を提案し、どのようなトレードオフが生まれるかを検討します。人工言語の設計としては、むしろこちらのほうが合理的であったり、世界観に刺さることが多いと考えます。

そもそも私たちは位取り記数法を使っていない

私たちは普段「10進数を使っている」と思っていますが、日常の言語運用まで含めると、この言い方は少し慎重に扱う必要があります。というのも、私たちが実際に口にしたり書いたりしているのは、桁の列そのものというより、「百」「千」「万」のような位を表す数詞を含んだ表現だからです。

例えば 3200 を読むとき、私たちは通常「三二〇〇」とは言わず、「三千二百」と言います。これは桁列をそのまま読んでいるのではなく、数をまとまり(単位)に分解して読んでいる、ということです。そしてこの分解は、103 や 104 といった対数的な節目に強く寄っています。日本語なら「万」、英語なら thousand や million といった語がそれに当たります。

すなわち、私たちは位を表す数詞で補助しながら数を扱っています。そして、その補助が半ば必須になっている以上、私たちは、そもそも「位取り記数法」を使っているわけではないのです。

そして、そのような「応急措置」があって初めて実用に足るのが位取り記数法なのであれば、最初から位取り記数法の問題を克服した合理的な記数法を用意することはできないのでしょうか?

記数法の評価軸

記数法を評価する観点として、少なくとも次の4つが考えられます。

  • 読み書きのしやすさ
  • 計算のしやすさ
  • 覚えやすさ
  • 拡張性

読み書きのしやすさとは、表現として簡潔かどうかという点です。例えば、最も原始的な記数法として「数の数だけ1本線を書く」ようなものが考えられますが、これは読み書きが大変です。なんたって「100」という数を表すのに100本の文字が必要になるのですから。

次に計算のしやすさ。例えば、素因数分解が非常にしやすい記数法があったとしても、四則演算が果てしなく難しいのであれば、私たちの日常生活には使えないでしょう。取り敢えずは四則演算がしやすいことが、現実的な前提条件になると思います。

覚えやすさとは覚えなきゃいけないものごとの多さです。例えば200進数で200文字覚えなきゃいけない、となると大変そうです。しかもその場合「九九」が81通りではなく、40000通りになりますから、その意味でも大変です。

最後に拡張性。例えば10進数は表現できる数に理論上限界はないですし、小数への拡張もできます。

位取り記数法の長所と短所

さて、一見すると位取り記数法(特に10進数)はこれらの点において優位に見えます。

  • 位取り記数法は、1から任意の自然数までの全ての数を表すための文字数の平均が常に最小になる記数法です。
  • 日常的なレベルであれば四則演算が行えます。
  • n通りの記号を覚えるだけですから、覚えるのも簡単です。
  • 拡張性も高く、並べるだけで無限の数を表現でき、小数も無限に細分化して表せます。

こうしてみると、確かに位取り記数法が最も優れた記数法であると考えるものがいてもおかしくありません。

しかし、本当でしょうか。

この議論は第一に、位取り記数法に有利な前提に無意識のうちに立っており、ほとんどトートロジーのような議論になっています。そもそも「数とはn個の記号のと一対一に対応する」という前提は、言語の線条性や形式素主義といった、位取り記数法文明の視点に強く依存します。

そして第二に、我々の実際の数の使用について、やや無頓着です。

「よく使う数」は短くあるべきだ

シャノンの暗号理論を持ち出すまでもなく、効率の良い言語使用の前提は「よく使うものは短く」「あまり使わないものは長く」です。では、私たちが日常で使う「数」にはどのような偏りがあるでしょうか。

よく知られている例として、以下のような偏りがあります。

  • 年号(2025など)や、ミームなど、文化的に意味のある数値は頻度が高くなる。
  • キリのいい数字は頻度が高い。
    • 73という数と1000という数では、1000の方が使用頻度は高い。
    • 発展途上国では年齢を自己申告させたとき、5歳刻みなどのキリの良い値に偏る現象(age heaping)がある。
  • 「先頭桁」は均一ではない(ベンフォードの法則)。
    • 人口、川の長さ、物理定数、財務データなど、あらゆる数値において「1」が先頭桁になる確率が3割程度なのに対し、9が先頭になる確率は5%もない
  • 整数の頻度分布がZipf則のような形に近づく。
    • 基本的に1や2といった小さい数と1001, 1002 といった数では頻度に大きな差がある。

そして、重要な点として、人間の量感覚は差よりも比に敏感であるということが挙げられます。そのため、多くの自然言語では、10を底とした対数上の特定区間ごとに「一」「十」「百」「千」「万」のように短い単語を当てています。日本語は位取り記数法そのものに加えて、10の倍数や10000の倍数の表現を強化しているとも言えます。

つまり、「よく使うものは短く」という原則と、「比を基準とした人間の量感覚」を整合した結果、「代表値」を等比数列で取る…というシステムが出来上がっています。

私たちは大きな数を扱えない

また、現実的な問題として、私たちは6桁以上の数値を把握することができません。計算したり、短期的に記憶したりすることも難しいですし、「0の数を間違える」など実際的な害もでてきます。

そのため、6桁を超えるならそもそも単位を見直すべきです。人口を表すなら「万人」「100万人」などを単位にするべきですし、例えば、アボガドロ定数のような大きな数を「602垓2140京7600兆」などと表すべきではないでしょう。

つまり、数が道具である以上、ある程度「上限」を持ってくれていたほうが使いやすいのではないかと思います。

標準数という考え方

であるなら、現実的な上限値を設定した上で、等比でスケールする記数表現を考えた方が、設計のトレードオフ上は良い気がします。実際工学の世界には、「標準数」という考え方があり、ボルトや抵抗など多くの規格で応用されています。最初は細かく、だんだん粗くする、という発想です。

この「上限」はどれくらいがいいのか…はどうしても恣意的になりますが、感覚的には数千〜数万あたりが一つの山場だと思っています。英語圏では10の3乗、日本語圏では10の4乗単位で丸めることが多いことも加味すればそれくらいがちょうど良い気がしています。

次に、倍率に関して見ていきましょう。これは「標準数」として使うときに荒すぎず、かつ刻みすぎないバランスを考える必要があります。

極端な例として、持っているお金を10の倍数の代表値(1,10,100,1000…)に丸めるとしましょう。316円を100円に丸めると-68%、1000円に丸めると+216%の誤差が生まれます。しかし、1.69倍ずつに代表値を取るなら、平均で13%、最大でも30%ほどの差で済みます。そうすれば自然な概数として利用できそうです。

許したい最大誤差 倍率 r 最大誤差(=√r−1) 平均誤差率(log一様のとき)
1割 1.21 10% 約 4.8%
2割 1.44 20% 約 9.1%
3割 1.69 30% 約 13.2%
4割 1.96 40% 約 17.0%

※「log一様」=「100〜200」と「1000〜2000」を同じ重みで見るような仮定。

ここまで言いたいことは単純です。位取り記数法は確かに有力なツールですが、その強さは「全ての整数を等しく大事に扱う」「数は桁列である」という前提と相性が良い、というだけの強さなのです。実際の使用頻度や、概数としての運用を考えれば、別の設計のほうが自然な場面が多いのです。

しかし、位取り記数法に代わる記数法など存在するのでしょうか。チャーチルの民主主義評よろしく、位取り記数法は「他よりマシだから一生付き合うべきもの」なのでしょうか。ここから先は、別の道を一本示してみます。


ゼッケンドルフ記数法

ここで提案する記数法は、数を複数の代表値の和として表現する「加法記数法」の一種です。加法記数法にはローマ数字や古代エジプト数字のように「時代遅れ」「原始的」というイメージがあるかもしれません。実際それらの体系が使い勝手が悪いのは事実ですが、それは単に洗練されていないからであって、加法記数法そのものには明確な強みがあると考えています。

この提案は、ゼッケンドルフの定理から着想を得ています。ゼッケンドルフの定理とは、任意の正の整数は、1つ以上の「番号が連続しない」フィボナッチ数の和として一意に表せる、というものです。すなわち、フィボナッチ数それぞれを「数字」として割り振れば、任意の自然数に一意な表現を割り振れます。

そこで、フィボナッチ数に文字を割り振ります。なおここでは、フィボナッチ数列の始まりが 0,1,1,2,3,5,8,... で1が2回出てくる点を、あえてそのまま採用します。たしかに1が2回出てくるのは「無駄」なので、合併してもよいのですが、ここでは、規則の単純さを優先して2つの1を残すことにします(この選択は設計上の好みで、正直、どちらでも良いです)。

割り振りは次の通りです。

対応するアルファベット 対応する値
a 0
b 1
c 1
d 2
e 3
f 5
g 8
h 13
i 21
j 34
k 55
l 89
m 144
n 233
o 377
p 610
q 987
r 1597
s 2584
t 4181
u 6765
v 10946

つまり、文字を並べることで、その和を表すというルールです。例えば hdh+d の意味で、13+2=15 です。順番は本質ではありません。

文字が有限なら表せる数に上限が出ますが、これは「〇〇番目のフィボナッチ数」を指定する演算子を用意することで解決します。

ここでは便宜的に <...> を「フィボナッチ番号指定」として使うことにします。例えば v の次が必要なら <22> (あるいは <ic> )のように書けます。そのため、理論上の上限はありません。

また、文字数に制限があることにはメリットもあります。上限があることで、「単位を見直す」きっかけになるからです。

文字数は多すぎても少なすぎても使いづらいです。個人的には22文字(17710まで演算子なしで表せる)あたりが覚えやすさと使いやすさのバランスが良いラインだと思っています。22番目の文字が10946で「だいたい1万」なのも10進数ユーザーにとって分かりやすいです。1億とか1兆くらいのオーダーが使いたいなら、v²やv³といった単位を使えば良いわけです。

ここから先は、この記数法を改めて評価し、位取り記数法(特に10進数)と比較します。評価軸は冒頭の4つ、読み書きの容易さ・覚えやすさ・演算・拡張性です。


読み書きの容易さ

ここでは読み書きの容易さの基準として、「何文字で表されるか」という点を検討します。位取り記数法では「桁数」に該当し、ゼッケンドルフ記数法では「項数」に該当します。

まず前提として、平均的には文字数は増えます。位取り記数法と違って「順番」に依存しない分、同じ文字数で表現できる組み合わせ総数が減りますし、ゼッケンドルフの正規形では長くなる数値が存在します。例えば 10945v の一つ前)は usqomkigec と10文字で示されます(ここでは正規形として「同じ文字を重ねず、隣り合うフィボナッチを同時に含まない」形を想定します)。

具体例として、0から9999までを等確率で取ったとき、平均使用文字数は10進数が約3.89文字であるのに対し、ゼッケンドルフ正規形では約5.28文字になります。

分布(0〜9999、等確率)の一例は次の通りです。

文字数 10進(個数) ゼッケンドルフ正規形(個数)
1 10 20
2 90 153
3 900 679
4 9000 1803
5 0 2901
6 0 2730
7 0 1381
8 0 313
9 0 20
指標(0〜9999) 10進 ゼッケンドルフ正規形
平均文字数 3.889 5.2811

ただし、ここには大事な但し書きがあります。これは「正規化された表現」で比較しているということです。10進数では「計算後」の表現が(基本的には)最も短くなります。一方でゼッケンドルフの世界では、計算して正規形に直すことが必ずしも最短表現ではありません。

例えば 10945 を表すだけなら、usqomkigec と書くより v - b と書いたほうが表現が短くなり、しかも「意味」が保存されます。なので、ゼッケンドルフ記数法を普段使いしているゼッケンドルフ原人がいたとして、彼らは不必要に計算してわざわざ表現を長くするような真似はしないでしょう。実際、項として負の数を認めるだけで、必要な項数の平均は大きく下がります。

さらに、言語使用は自然と最適化していくものです。順番がないことを利用して「降順のときは和として扱い、昇順のときは積として扱う」のようなルールを設定することで、hf は「18」だが fh は「65」…というように表現を分けるかもしれません。結局のところ、ちゃんと比較するなら、10進数を使ってる日常世界とゼッケンドルフを使っている日常世界における「それぞれの数の出現頻度」も考慮に入れるべきです。

2つの世界を比較すると、結局平均文字数はそんなに変わらないと考えます。というのも、ゼッケンドルフ世界では「代表値」(フィボナッチ数)が対数的に並び、概数としての丸め誤差が小さいため、1文字で表現される数値の使用頻度が高くなると予想できるからです。結局のところ数字とは道具ですから、「使いやすさ」によって出現する数の頻度は変わりうるわけです。

そんなわけで、「読み書きの容易さ」は簡単に比較できるものでもなさそうですが、少なくとも次は言えそうです。

  • 正確にすべての数を書く用途では、平均文字数の点で位取り記数法がやや優位
  • 概数で運用する用途では、ゼッケンドルフ側のほうが自然に「丸めやすい」構造を持つ

覚えやすさ

覚えやすさについては、結論から言えば、ここに大きな差はないと考えます。覚えやすさには、記数法の「ルールとしての覚えやすさ」と、用いる「文字(記号)の覚えやすさ」という二つの側面があると思います。

第一に、ルールとしての覚えやすさとは、ある表記を数として解釈するために必要な構造の理解のしやすさのことです。10進数では、XYZという並びを 100*X + 10*Y + Z のように位ごとの重みづけとして解釈する必要があります。一方でゼッケンドルフ記数法では、基本的には書かれた文字が表す値の和として解釈すればよく、対応関係がより素朴です。

第二に、文字(記号)の覚えやすさについてです。位取り記数法は底の数だけ記号を覚える必要があり、10進数なら10種類です。ゼッケンドルフの場合は「どこまでのフィボナッチ数に文字を割り当てるか」に依存しますが、今回提案する運用では22文字を想定しています。

こうして見ると、純粋に記号の種類だけを数えるなら10進数のほうが僅かに有利にも見えます。ただ、自然言語として運用することを考えると、10進数も実際には「十・百・千・万・億・兆…」といった数詞を併用せざるを得ず、覚えるべき語彙は増えます。これを加味すると、両者の差は実用上ほとんど変わらないように見えます。

総じて、覚えやすさという点では、大きな差はなさそうです。


演算のしやすさ

この点が一番、違いが出やすいところかもしれません。私たちが日常で使う計算は主に次の3つだと考えます。そのため、この3つについて比較・検討していきましょう。

  1. 足し算と引き算
  2. 掛け算と割り算
  3. 因数分解(倍数判定)

1. 足し算・引き算

さて、ゼッケンドルフ記数法の足し算は驚くほど簡単です。例えば h+d はなんでしょうか。そう、hd ですね。hd とは hd を足したものなんですから。では f+k は? kf です。足したものを書き連ねるのが加法記数法なんです。

ただし、いつでもただ並べればよいわけではありません。ゼッケンドルフ記数法では、表現を正規形に整えるために、いくつかの規則を適用します。

c+d はどうなるでしょうか。こちらは dc ではありません。隣り合っているフィボナッチ数同士は合体します。つまり c+d=e です。隣り合っている文字は、さらにその次の文字になります。

最後に e+e を見てみましょう。同じ文字が二つ並んだとき用の置き換え規則が作れます。ecd の合体ですから、e+e は「ecd が並んだもの」と同じです。すると ed が隣り合っているので合体して f になり、残りは fc、すなわち fc です。よって e+e=fc です。

お分かりでしょうか。結局のところ、足し算は「並べる」こと自体が計算の本体で、あとは表現を整えるだけです。整え方も、次の二つを繰り返すだけで済みます。

  • (1) 同じ文字が二つあれば、その文字を「二つ前」と「一つ先」に置き換える。
  • (2) 隣り合う文字があれば、ひとつ上の文字に合体させる。
  • (1)(2)を、どちらも適用できなくなるまで繰り返せば終わり。

この世界に、繰り上がりの足し算で苦労する小学生などいないのです。慣れれば算盤のように、一瞬で計算できるようになるでしょう。

2. 掛け算・割り算

次に掛け算です。掛け算と言われて複雑な九九を覚える必要があるのでは……と身構えたかもしれません。しかし、こちらも「手続き」さえ覚えてしまえば、何一つ計算結果を覚える必要はないのです。百聞は一見に如かず。実際にこの世界における「九九」の表をご覧いただきましょう。

× c d e f g h i
c c d e f g h i
d d ec fd ge hf ig jg
e e fd gc he if jg kh
f f ge he jfc kgc lhd mge
g g hf if kgc lfc mge nhf
h h ig jg lhd mge njfc ogc
i i jg kh mge nhf ogc plhd

アルファベットの順番に慣れてないとこの表を見てもピンとこないかもしれないので、同じ内容を「フィボナッチの番号」で書いたものもお見せします。ここでは、フィボナッチ数列のうち [n] を「n 番目のフィボナッチ数」とします(0 始まりで、[0]=0, [1]=1, [2]=1, [3]=2, [4]=3, [5]=5, [6]=8, [7]=13, [8]=21, …)。対応は a=[0], b=[1], c=[2], d=[3], e=[4], f=[5], g=[6], h=[7], i=[8] です。九九表は見通しのために [2](=c)から載せます。なお [1] を掛ける場合は [1]×[n]=[n] です。

× [2] [3] [4] [5] [6] [7] [8]
[2] [2] [3] [4] [5] [6] [7] [8]
[3] [3] [4]+[2] [5]+[2] [6]+[3] [7]+[4] [8]+[5] [9]+[6]
[4] [4] [5]+[2] [6]+[2] [7]+[3] [8]+[4] [9]+[5] [10]+[6]
[5] [5] [6]+[3] [7]+[3] [8]+[4]+[2] [9]+[5]+[2] [10]+[6]+[3] [11]+[7]+[4]
[6] [6] [7]+[4] [8]+[4] [9]+[5]+[2] [10]+[6]+[2] [11]+[7]+[3] [12]+[8]+[4]
[7] [7] [8]+[5] [9]+[5] [10]+[6]+[3] [11]+[7]+[3] [12]+[8]+[4]+[2] [13]+[9]+[5]+[2]
[8] [8] [9]+[6] [10]+[6] [11]+[7]+[4] [12]+[8]+[4] [13]+[9]+[5]+[2] [14]+[10]+[6]+[2]

つまり以下の三つのルールを順番に見ていけば自然と答えが出てしまいます(m>n とします。ここでの m, n はフィボナッチの「番号」で、上の表の [n] の n に相当します)。

  1. [m]×[n] の先頭(最大)の項は、必ず [m+n-2] です。
  2. そこから先は、基本的に 4 つずつ番号が減った項が並びます([m+n-2], [m+n-6], [m+n-10], …)。
  3. 最後の終わり方だけが偶奇で変わります。n が偶数のときは最後が [m-n+2] で終わり、n が奇数のときは最後だけ差が 3 になって [m-n+1] が追加されます。

つまり、ゼッケンドルフ原人は繰り上がりの計算に苦しむどころか、「九九」を覚える必要すらないのです!

四則演算とトレードオフ

さて、ここまで加算と乗算の方向性について、それぞれ極めて単純な規則や手続きで処理できることを示しました。ただし、ゼッケンドルフ記数法には短所もあります。一回一回の操作は楽な代わりに、必要になる操作回数が多いのです。

ただし、そのデメリットを踏まえても、私はゼッケンドルフ記数法を使った方が全体としての計算効率は上がるだろうと主張します。結局、一回一回の操作のハードルが低い方が、たとえ操作回数が増えても計算ミスが減ると思うからです。この思想は算盤にも似ています。難しい計算を論理的に組み立てるより、単純な操作を何度も繰り返した方が、最終的な出力は早く、確実になるのです。

3. 因数分解

さて、普段意識しない10進数のメリットとして、因数分解(あるいは倍数判定)のしやすさというものがあります。2や5で割り切れるかどうかは一見して分かりますし、他の9までの数についても比較的簡単な倍数判定が知られています。これはすごいことですし、普段意識していないだけで、私たちはこの恩恵にあやかっていると思います。

では、ゼッケンドルフ記数法ではどうでしょうか。結論から言えば、こちらも一貫した倍数判定の方法があります。ある数がmの倍数かどうかを知りたければ、各文字(=各フィボナッチ数)をmで割った余りを足し合わせ、最後にその和が0になるかどうかを見ればよいのです。

ここで重要なのは、フィボナッチ数列をmで割った余りの並びが必ず周期的になる、ということです。したがって、mごとに「余り表」を作っておけば、倍数判定は「表を参照して足す」だけになります。慣れれば暗算でも扱えます。

例として2の倍数判定を考えます。フィボナッチ数は3つおきに偶数になります(例:0,1,1,2,3,5,8,13,21,34,... )。したがって「偶数項か奇数項か」を数えるだけで判定できます。10進数の3の倍数の判定方法と基本的には同じことをすべての数で行えるのです!

このように、ゼッケンドルフ記数法では倍数判定の方法が統一されます。10進数は底(10)の性質によって2と5が特別に扱いやすい一方で、ゼッケンドルフ記数法は「任意のmに対して、余り表を作って足す」という同じ手続きで処理できるのです。もちろん因数分解そのものが魔法のように簡単になることはありませんが、割れるかどうかを確かめるための単純な手続きが揃っているのは便利です。


拡張性

最後に拡張性についてです。ここでいう拡張性には二つあります。第一に「どこまでも大きな整数を書けるか」。第二に「小数のように、精度を上げていけるか」です。

大きな整数への拡張

10進数は桁を重ねることで無限大に数を拡張できます。ゼッケンドルフ記数法も先に述べたように「〇〇番目のフィボナッチ数」を指定する演算子(ここでは <...>)を用意すれば無限大に数を表現できます。例えば v までしか定義していないとしても、その次のフィボナッチ数は <ic> のように書けます。
つまり、整数の表現能力という意味では、位取り記数法と同様に理論上限界はありません。

小数への拡張

小数についても、位取り記数法と同様に拡張することができます。

ここで一つ、加法記数法らしい拡張として「逆数」を使う案が出てきます。例えば「u は 6765 を表す」なら「[u] は 1/6765 を表す」といった具合に、逆数を表す記法を追加します。すると、逆数の和で有理数(あるいは実数の近似)を作れます。例えば「(1/2)x + (1/3)y + (1/5)z + ...(x,y,zは各逆数を使うかどうかのブール)」のように、選択の和として数を近似していくことで、小数のようなものが作れます。

ただし、ここで二つの論点が出ます。

  • その表現が一意になるか(ゼッケンドルフのような一意性が保てるか)。
  • そもそも「全部の逆数を足したとき」にどこへ収束するか(表現範囲がどうなるか)。

表現の一意性については成立しそうですし、逆数和についても、約 1.359... 程度の値に収束します。ただし、ゼッケンドルフの定理と同じようには正規化できないため、実際にどのようにこの小数が使われうるか…という点については課題が残っています。

したがって、現時点での結論としてはこうなります。

  • ゼッケンドルフ記数法は整数については拡張性に困らない。
  • 任意の有理数を表すことができるうえ、小数のような拡張を考えることができる。

まとめ

ここまでの議論を整理します。

位取り記数法(特に10進数)は、確かに優秀です。読み書き、演算、覚えやすさ、拡張性のすべてを兼ね備えています。しかしその優秀さは「すべての数を等しく丁寧に扱う」「数は桁列である」という前提と強く結びついていますし、実際の言語使用では位を表す数詞を後付けして「補助」しています。実際の数の使用頻度や、概数としての運用、あるいはではない表現を考えると、別の合理性が俎上に上がります。

ゼッケンドルフ記数法は、いわばその別の合理性を体現しているのです。ゼッケンドルフ記数法には以下の特徴があります。

  • 概数として丸め誤差が小さく、使いやすい。
  • 覚えやすい。
  • 足し算は簡単なアルゴリズムで実行できる
  • 掛け算も簡単なアルゴリズムで実行できる。
  • 因数分解(倍数判定)も、一貫した手続きとして整理できる。
  • 整数においても、小数においても、十分な拡張性が保証されている。

人工言語作者が「何進数にするか」だけを議論しているなら、その時点で設計空間の大部分を捨てていることになるかもしれません。この記事が、あなたが記数法を考える際の僅かなヒントになることを望んでいます。

以上。

Top comments (0)