有理数の付番

概要

有理数の付番の計算しやすい定義を与えた。

はじめに

有理数 (\mathbb{Q}) は自然数 (\mathbb{N}) と同じくらいの個数しかない(可算)というのはよく知られています。これは通常、以下のような理屈で納得されます。

  • 0, 1, -1, 2, -2, 3, -3, \ldots のように付番することで、 \mathbb{Z}\mathbb{N} と同じくらいしかないことがわかる。
  • (0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), \ldots のように付番することで、 \mathbb{N} \times \mathbb{N}\mathbb{N} と同じくらいしかないことがわかる。
  • \mathbb{Q} は分子と分母の組で表せるので、 \mathbb{N} と同じかそれより少ないとわかる。
  • 一方、自然数はそのまま有理数なので、 \mathbb{N}\mathbb{Q} と同じかそれより少ないとわかる。
  • したがって、 \mathbb{N}\mathbb{Q} は同じくらいしかない (この推論をCantor-Bernstein-Schröderの定理という)

しかし以下のようにすると、具体的な付番を与えることができます:

了解1.1 \mathbb{N} は0以上の整数全てからなる集合を指すこととする。自然数という言葉も同様の意味で用いる。 また、 \mathbb{N}^+ を1以上の整数全てからなる集合とする。

定義1.2 f\colon \mathbb{Q} \to \mathbb{N} を以下のように定義する。

  •  f(q) = 2f(1 / (q - 1)) + 2     (1 \lt q の場合)
  •  f(q) = 2f(1 / q - 1) + 1     (0 \lt q \le 1 の場合)
  •  f(q) = 0              (q = 0 の場合)
  •  f(q) = 2f(1 / q + 1) + 2     (-1 \le q \lt  0 の場合)
  •  f(q) = 2f(1 / (q + 1)) + 1     (q \lt -1 の場合)

証明

では、これが実際に付番として機能することを証明していきます。証明とかよくわからない人は飛ばしてもOKです。

定理1.3 f は矛盾なく定義される。

(証明) 方程式中の除算は以下のように正当化される。

  • 1番目の方程式では 1 \lt q より 0 \lt q - 1 となるため、除算可能。
  • 2番目の方程式では 0 \lt q より除算可能。
  • 4番目の方程式では q \lt 0 より除算可能。
  • 5番目の方程式では q \lt -1 より q + 1 \lt 0 となるため、除算可能。

また f の結果に対しては2をかける操作と1または2を足す操作しかしていないから、 \mathbb{N} の範疇に収まる。

あとは、この方程式の解がちょうど1つあることを示せばよい。そのためには f(q) の値が q の何らかの順序にしたがって順番に決定されることを示せばよい。そのような指標としてここでは以下のようなものを考える。 a \in \mathbb{Z}, b \in \mathbb{N}^+, \mathrm{gcd}(a, b) = 1 に対し、 |-|_f \colon \mathbb{Q} \to \mathbb{N}

\displaystyle |a/b|_f = |a| + |b|

と定める。(有理数はこのような a, b の組で一意に表せるので、ちゃんと定義される)

f(q) の値が |q|_f の小さいほうから順に定まるということを示したい。上記の方程式は q に関する漏れや重複のない場合分けになっているので、各方程式をそれぞれ見ていけばよい。

  • 1番目の方程式では b \lt a として f(a/b)f(b / (a - b)) で表している。ここで ba - b は互いに素のため、 |b / (a - b)|_f = |b| + |a - b| \lt |b| + |a| = |a / b|_f となる。したがって既に定まっている値を使って f(a/b) を表している。
  • 2番目の方程式では 0 \lt a \le b として f(a/b)f( (b - a) / a) で表している。ここで b - aa は互いに素のため、 |(b - a) / a|_f = |b - a| + |a| \lt |b| + |a| = |a / b|_f となる。したがって既に定まっている値を使って f(a/b) を表している。
  • 3番目の方程式はダイレクトに f(a/b) を表しているので問題ない。
  • 4番目の方程式では -b \le a \lt 0 として f(a/b)f(-(b + a) / -a) で表している。ここで -(b + a)-a は互いに素のため、 |-(b + a) / -a|_f = |-(b + a)| + |-a| = |b + a| + |a| \lt |b| + |a| = |a / b|_f となる。したがって既に定まっている値を使って f(a/b) を表している。
  • 5番目の方程式では a \lt -b として f(a/b)f(-b / -(a + b)) で表している。ここで -b-(a + b) は互いに素のため、 |-b / -(a + b)|_f = |-b| + |-(a + b)| = |b| + |a + b| \lt |b| + |a| = |a / b|_f となる。したがって既に定まっている値を使って f(a/b) を表している。

定理1.4 f全単射である。

まずは前者(全射)を示す。全射を示すためには、 n \in \mathbb{N} とおいて、 f(q) = n となる q \in \mathbb{Q} の存在を示せばよい。これを n に関する数学的帰納法 (累積帰納法) によって示す。

n = 0 のとき、 q = 0 とおけばよい。

n > 0 のときはさらに n の偶奇で場合分けする。 n が奇数のとき、 m \in \mathbb{N} を用いて n = 2m + 1 と表記できる。m \lt n なので数学的帰納法の仮定より f(r) = m となる r \in \mathbb{Q} が存在する。

さらに r の符号で場合分けする。 r \ge 0 のとき、 q = 1 / (r + 1) とおく。すると 0 \lt q \le 1 より f(q) = 2f(1 / q - 1) + 1 = 2f(r) + 1 = 2m + 1 = n となる。 r \lt 0 のときは、 q = 1 / r - 1 とおく。すると q \lt -1 より f(q) = 2f(1 / (q + 1)) + 1 = 2f(r) + 1 = 2m + 1 = n となる。

n が(正の)偶数のとき、 m \in \in \mathbb{N} を用いて n = 2m + 2 と表記できる。 m \lt n なので数学的帰納法の仮定より f(r) = m となる r \in \mathbb{Q} が存在する。

こちらも r の符号で場合分けする。 r > 0 のとき、 q = 1 / r + 1 とおく。すると  1 \lt q より f(q) = 2f(1 / (q - 1)) + 2 = 2f(r) + 2 = 2m + 2 = n となる。 r \le 0 のときは、 q = 1 / (r - 1) とおく。すると  -1 \le q \lt 0 より f(q) = 2f(1 / q + 1) + 2 = 2f(r) + 2 = 2m + 2 = n となる。

以上により f全射であることが示された。

続いて単射を示す。単射を示すためには、 q, q' \in \mathbb{Q} とおいて f(q) = f(q') なら q = q' を示せばよい。これを f(q) に関する数学的帰納法(累積帰納法)によって示す。

f(q) = f(q') = 0 のとき q = q' = 0 である。これは1番目、2番目、4番目、5番目の方程式が当てはまらないことからわかる。

f(q) = f(q') > 0 の場合、さらに偶奇で場合分けする。 f(q) = f(q') が奇数のとき、1,3,4番目の方程式は当てはまらないので、 q \lt -1 または 0 \lt q \le 1 である。 q' についても同様に q' \lt -1 または 0 \lt q' \le 1 である。ここで q \lt -1 なら r = 1 / (q + 1)0 \lt q \le 1 なら r = 1 / q - 1 と定義する。また同様に r' も定義する。すると f(q) = 2f(r) + 1, f(q') = 2f(r') + 1 となる。特に f(r) = f(r') \lt f(q) なので、数学的帰納法の仮定より r = r' がわかる。ここで、 r = r' \ge 0 なら q = 1 / (r + 1) = 1 / (r' + 1) = q' となり、 r = r' \lt 0 なら q = 1 / r - 1 = 1 / r' - 1 = q' となる。

同様に、 f(q) = f(q') が(正の)偶数のとき、2,3,5番目の方程式は当てはまらないので、 -1 \le q \lt 0 または 1 \lt q である。 q' についても同様に -1 \le q' \lt 0 または 1 \lt q' である。ここで -1 \le q \lt 0 なら r = 1 / q + 11 \lt q なら r = 1 / (q - 1) と定義する。また同様に r' も定義する。すると f(q) = 2f(r) + 2, f(q') = 2f(r') + 2 となる。特に f(r) = f(r') \lt f(q) なので、数学的帰納法の仮定より r = r' がわかる。ここで、 r = r' > 0 なら q = 1 / r + 1 = 1 / r' + 1 = q' となり、 r = r' \le 0 なら q = 1 / (r - 1) = 1 / (r' - 1) = q' となる。

以上により f単射であることが示された。

原理

有理数に付番する場合、約分できる分数に番号を与えないようなトリックが必要です。これは通常、約分できる分数を見つけるたびにスキップするような方法で対処しますが、この定義ではユークリッドの互除法の手順をそのままエンコードすることで、はじめから互いに素なペアだけを発見するような仕組みになっています。

まずは正の整数2つユークリッドの互除法エンコードすることを考えます。たとえば33と57の互除法は以下のようになります。

  • 57, 33
  • 33, 24 (57を33で割った余り)
  • 24, 9 (33を24で割った余り)
  • 9, 6 (24を9で割った余り)
  • 6, 3 (9を6で割った余り)
  • 3, 0 (6を3で割った余り)

これを復元するには、各段階での商を覚えておけばいいです。つまりこの場合は (1, 1, 2, 1, 2) となります。これを逆順に再生することにより

  • 1, 0 (初期状態)
  • 2, 1 (1を2倍して0に足す)
  • 3, 2 (2を1倍して1に足す)
  • 8, 3 (3を2倍して2に足す)
  • 11, 8 (8を1倍して3に足す)
  • 19, 11 (11を1倍して8に足す)

と、約分された状態の互除法が復元できます。

ただこの方法をそのまま使うと、次のステップで整数の列を自然数エンコードしなくてはならなくて面倒です。そこで互除法の亜種として、互減法を考えます。

  • 57, 33
  • 24, 33 (左を引く)
  • 24, 9 (右を引く)
  • 15, 9 (左を引く)
  • 6, 9 (左を引く)
  • 6, 3 (右を引く)
  • 3, 3 (右を引く)

またちょっとした工夫として、0が出てきたら終わりではなく、左右が同じになったら終わりということにしておきます。

こうすると、左右のどちらから引いたかを覚えておけば復元できます (左、右、左、左、右、右)。

しかも嬉しいことに、この計算は分数としても簡単な計算に対応します。左を分子、右を分母とする場合、左から引く操作は1を引く操作に対応します。右から引く操作は逆数をとり、1を引いてまた逆数をとる操作に対応します。

いっぽう、 (左、右、左、左、右、右) のようなビット列を自然数に埋め込むときは、2進法を使うことができます。このとき、最上位ビットに番兵ビットとしての1を常に置くことによって、列の長さも自然にエンコードできます。つまり、

  • 1 は2進法で 1 なので空のビット列
  • 2 は2進法で 10 なので (0) というビット列
  • 3 は2進法で 11 なので (1) というビット列
  • 4 は2進法で 100 なので (0, 0) というビット列
  • 5 は2進法で 101 なので (0, 1) というビット列
  • 6 は2進法で 110 なので (1, 0) というビット列
  • 7 は2進法で 111 なので (1, 1) というビット列
  • ...

となります。初期値は1で、0を付加するときは2倍、1を付加するときは2倍して1を足せばいいことになります。

この場合実際には正の整数にエンコードしていることになるので、非負整数として書くときにはうまく1ずつずらす必要があります。つまり、

  • 初期値は0
  • 0を付加するときは2倍して1を足す
  • 1を付加するときは2倍して2を足す

というルールになります。

これを使って、正の有理数自然数エンコードする関数は以下のように書けます。

  •  f(q) = 2f(q - 1) + 1     (1 \lt q の場合)
  •  f(q) = 0              (q = 1 の場合)
  •  f(q) = 2f(1 / (1 / q - 1)) + 2     (0 \lt q \lt 1 の場合)

これを改良していきます。まず、単に見た目の問題ですが、1番目の方程式と3番目の方程式がアンバランスなので工夫します。1ステップごとに分母と分子を入れ替えるルールにすると、逆数を取る処理を公平に負担することができます。

  •  f(q) = 2f(1 / (q - 1)) + 1     (1 \lt q の場合)
  •  f(q) = 0              (q = 1 の場合)
  •  f(q) = 2f(1 / q - 1) + 2     (0 \lt q \lt 1 の場合)

次に、ゼロと負の有理数に対応する必要があります。負の数は負の数のなかでループすることにして、符号のために1ビット追加することでうまく対処できます。

  •  f(q) = 2f(1 / (q - 1)) + 1     (1 \lt q の場合)
  •  f(q) = 1              (q = 1 の場合)
  •  f(q) = 2f(1 / q - 1) + 2     (0 \lt q \lt 1 の場合)
  •  f(q) = 0              (q = 0 の場合)
  •  f(q) = 2f(1 / q + 1) + 2     (-1 \lt q \lt 0 の場合)
  •  f(q) = 2              (q = -1 の場合)
  •  f(q) = 2f(1 / (q + 1)) + 1     (q \lt -1 の場合)

さらに場合分けを減らすために、 q = 1 の場合と q = -1 をいい感じに統合します。このとき、 f(0) = 0 かつ f(1) = 1 となるようにビットの値も調整しておきます。 (何となくそのほうが綺麗なので)

  •  f(q) = 2f(1 / (q - 1)) + 2     (1 \lt q の場合)
  •  f(q) = 2f(1 / q - 1) + 1     (0 \lt q \le 1 の場合)
  •  f(q) = 0              (q = 0 の場合)
  •  f(q) = 2f(1 / q + 1) + 2     (-1 \le q \lt 0 の場合)
  •  f(q) = 2f(1 / (q + 1)) + 1     (q \lt -1 の場合)

これで冒頭の定義になりました。

まとめ

有理数の付番を、比較的簡単な方程式で与えることができました。これはユークリッドの互除法をうまくエンコードすることによって作られています。

ところで \mathbb{Q} といえば、最近Qiitaというサービスで記事を書いてみました。ぶっちゃけはてなブログより使いやすくて、技術記事を書くには快適でよいですね。気まぐれに使いわけてみようと思っています。