ブログの説明

学校に通わないで学んだことを記しています。間違っているところが何かありましたらご指摘下さると幸いです。コメントに対する返信が遅れる可能性があります。その場合は申し訳ありません。

このブログではサイドバーに広告を表示しています。このブログ内の投稿記事を検索するには右上の拡大鏡のアイコンを、アーカイブやラベル付けから投稿記事を閲覧するには左上の三重線のアイコンをクリックして下さい。

数式の表示にはMathJaxを利用させていただいています。数式の表示のためにJavaScriptが有効である必要があります。そうでない場合、訳の分からないLatexのコードが表示されます。幾何学図形やチャートの表示にはHTML5 CanvasやGoogle Chartを使用しています。その表示のためにもJavaScriptが有効である必要があります。

10の補数と9の補数と2の補数と1の補数

10進数と10の補数

10進法の四則演算に慣れている人なら算術的な直感で分かるのが10の補数。算盤そろばんを使っている人は10の補数と5の補数を出力する函数を会得しているかもしれない。

例えば、2に対して10の補数はいくつかと問われればそれは8だと分かるし、6に対して10の補数はいくつかと問われればそれは4だと分かるし、5に対して10の補数はいくつかと問われれば5だと直感的に分かる。

また、3に対して5の補数はいくつかと問われればそれは2だと分かるし、2に対して5の補数はいくつかと問われれば3だと分かる。

10の補数とは、ある自然数に対してそれにいくつの自然数を加えれば10になるのかという問いに答えたもの。自然数とは、ここでは0, 1, 2, 3, 4, 5, 6, 7, 8, 9のこと。

ある自然数xに対する10の補数yは次のように計算することによって答えることができる。

\[ y = 10 - x \]

10進法の位取り記数法では、桁上がり(位上がり)が起こる数が10であるので、ある数にあといくつ足すと桁上がりが起こるかを理解していることは、その四則演算においてとても重要な暗記事項になっている。

10進法の四則演算に慣れた人の頭の中には次のような函数または対応表があるのかもしれない。

\[ f(x) = 10 - x \]

xは引数。「xに対する10の補数」を出力してくれる函数f(x)。

10の補数の対応表
10進数 10の補数
0 10
1 9
2 8
3 7
4 6
5 5
6 4
7 3
8 2
9 1
10 0

補数のこの対応表を見ると、数値を小さい順から並べた昇順と数値を大きい順から並べた降順との写像(マッピング)関係に見える。

10の補数と桁上がり

例えば、\( 6 + 7 = \)を計算するとき、人は6または7の補数を瞬時に思い浮かべ、加える数がそれを上回っている場合に桁上がりが起こると即座に認識するはず。つまり、6に対する10の補数である4を思い浮かべ、その4より大きい7から4を引いた数である3と10を足し合わせて答えを計算するかもしれない。

\[ \begin{align*} 6 + 7 &= 7 - (10 - 6) + 10 \\ &= 7 - 4 + 10 \\ &= 3 + 10 \\ &= 13 \end{align*} \]
\[ \begin{align*} 6 + 7 &= 6 - (10 - 7) + 10 \\ &= 6 - 3 + 10 \\ &= 3 + 10 \\ &= 13 \end{align*} \]

数学者ガウスの逸話

余談になるけれども、10の補数の対応表を見て数学者ガウスの10歳のころの逸話を連想した人がいるかもしれない。

1から100まで順番に足したらその答えはいくつになるか、と先生が生徒に課題を出した。

\[ x = 1 + 2 + 3 + \cdots + 98 + 99 + 100 \]

この課題に対してガウス少年が思わぬ速さで答えを出した。このときにガウス少年が用いた速算術は次のようなものだったのかもしれない。

足し算は足す順番を置き替えても答えは同じ。だとすれば、手っ取り早く計算するにはどの順番で足したら合理的か。そこで補数の考え方を利用すればいい。つまり次のように101の補数を考える。

\[ \begin{align*} x &= (1 + 100) + (2 + 99) + (3 + 98) + \cdots \\ & \cdots + (48 + 53) + (49 + 52) + (50 + 51) \\ x &= \underbrace{101 + 101 + 101 + \cdots + 101 + 101 + 101}_{101が50個} \\ x &= 101 \times 50 \\ x &= (101 \times 5) \times 10 \\ x &= 5050 \end{align*} \]

そういう訳で、その答えは5050となる。

101の補数
10進数 101の補数
1 100
2 99
3 98
\( \vdots \) \( \vdots \)
48 53
49 52
50 51

ただし、ガウス少年のこの逸話が真実であったかどうかを疑問視する説もある。

ちなみに、この等差数列の合計を出すための公式が知られていて、それは次のようなもの。

1ずつ増えていく、つまり公差1の等差数列が1からnまであるとする。

\[ 1, 2, 3, 4, \cdots, n \]

それらの数の合計Sを出すには次の公式を用いることができる。

\[ S = \dfrac{n(n+1)}{2} \]

つまり、nにn+1をかけてその答えを2で割ることでその数列を合計した数が分かる。

例えば、1から86までの自然数を順番に足した場合、その合計はこうなる。

\[ \begin{align*} \dfrac{86 \times (86 + 1)}{2} &= \dfrac{86 \times 87}{2} \\ &= \dfrac{43 \times 87}{1} \\ &= \dfrac{3741}{1} \\ &= 3741 \end{align*} \]

R言語の対話式インタプリタを起動して答え合わせをしてみた。

$ R
(中略)
> a = c(1:100)
> a
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
 [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
 [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
 [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
 [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
 [91]  91  92  93  94  95  96  97  98  99 100
> sum(a)
[1] 5050
> 100*(100+1)/2
[1] 5050
> b = c(1:86)
> b
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
[26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
[51] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
[76] 76 77 78 79 80 81 82 83 84 85 86
> sum(b)
[1] 3741
> 86*(86+1)/2
[1] 3741
> q()

c(1:100)で1から100までの数列(R言語ではベクトルと呼ぶ)を作り、aに代入。そのaをsum()函数に渡してその数列の合計を求めた。sum()函数が出した値と公式による計算結果の値とが一致していることが分かる。

10進数と9の補数

9の補数は、ある自然数を9にするためにいくつ加える必要があるかという問いに答えるもの。

例えば、1に対して9の補数は8であるし、3に対して9の補数は6であるし、7に対して9の補数は2であると分かる。

9の補数をyとすると、ある自然数xに対する9の補数yは次の式によって計算することができる。

\[ y = 9 - x \]

9の補数は引き算の答えを足し算によって出すときに利用することができる。とはいえ、補数を知るために引き算をあらかじめしているのだから、引き算を用いていないということにはなりそうにないけれども。

具体例を挙げてみる。例えば\( 5632 - 3674 = \)の計算を9の補数を使ってやってみる。

アルゴリズム

  1. 5632の各々の桁の値に対して9の補数を求める。5が9になるためには4足りない。6が9になるためには3足りない。...その結果、5632に対する9の補数は4367だと分かる。
  2. 5632に対する9の補数である4367と3674を足す。その答えは8041となる。
  3. 8041の各々の桁の値に対して9の補数を求める。8が9になるには1足りない。0が9になるには9足りない。...その結果、8041に対する9の補数は1958だと分かる。
  4. この1958と\( 5632 - 3674 \)とは等しい。
\[ \begin{align*} 5632 - 3674 &= 9999 - (3674 + (9999 - 5632)) \\ &= 9999 - (3674 + 4367) \\ &= 9999 - 8041 \\ &= 1958 \end{align*} \]

2進数と1の補数

2進法で用いられる補数には1の補数と2の補数がある。

2進法において1の補数の対応表は次のように単純なもの。否定の真理値表と同様になる。

1の補数の対応表
2進数 1の補数
0 1
1 0

2進法の0に対する1の補数は0。2進数の1に対する1の補数は0。

このように、2進法における0または1に対する補数は否定の真理値表と同じ結果になるので、コンピュータ上では、ある値を入力するとその補数が出力される論理回路をNOTゲートを用いて簡単に実現しやすい。

補数を求めるためにわざわざ引き算の回路を作る必要がないことをこのことは意味している。NOTゲートを使えば引き算も足し算としてコンピュータの中で計算することあできる。

例えば\( 1011 - 101 = \)を計算してみる。これは10進法では\( 11 - 5 = \)に相当している。

  1. 2進数の1011に対する1の補数は、NOTゲートを通過すると0100になる。
  2. 100と101を足すと1001になる。
  3. 1001がNOTゲートを通過すると0110、すなわち110になる。

Python3の対話式インタプリタを起動して答え合わせ。

$ python3
(中略)
>>> a = int("0b1011",2)
>>> b = int("0b101",2)
>>> c = a - b
>>> bin(c)
'0b110'
>>> quit()
$

0bは2進数を表わす接頭辞。int()函数で2進数を10進数に変換してから引き算をし、bin()函数を用いてその答えを2進数に戻した。期待したとおり0b110が得られた。

コンピュータ上で4ビット(すなわち4桁)のデータを表わすことを考えると、その場合の2進数とその1の補数との対応表は次のとおり。

4ビット2進数と1の補数
4桁の2進数 1の補数
0000 1111
0001 1110
0010 1101
0011 1100
0100 1011
0101 1010
0110 1001
0111 1000
1000 0111
1001 0110
1010 0101
1011 0100
1100 0011
1101 0010
1110 0001
1111 0000

2進数と2の補数

2進法において2の補数は、10進法において10の補数と同様に、ある2進数にいくつ加えれば桁上がりが起こるかに答えるもの。

2の補数は1の補数に1を加えることによって計算することができる。

  1. NOTゲートを通して1の補数を出す。
  2. その1の補数に1を加える。

例えば2進数の10110に対する2の補数は次の手順で求まる。

  1. 10110をNOTゲートに通すと01001になる。
  2. \( 01001 + 1 = 01010 \)となる。

2進数の10110に対する2の補数は1010であることが分かった。

2の補数
2進数 2の補数
0 10
1 1

コンピュータ上で4ビット(すなわち4桁)のデータを表わすことを考え、その場合の2進数とその1の補数及びその2の補数の対応表を作ってみた。それは次のとおり。1の補数は2の補数から1引いた数、2の補数は1の補数に1足した数になっていることが分かる。

4ビット2進数と1及び2の補数
4桁の2進数 1の補数 2の補数
0000 1111 10000
0001 1110 1111
0010 1101 1110
0011 1100 1101
0100 1011 1100
0101 1010 1011
0110 1001 1010
0111 1000 1001
1000 0111 1000
1001 0110 0111
1010 0101 0110
1011 0100 0101
1100 0011 0100
1101 0010 0011
1110 0001 0010
1111 0000 0001

2の補数の10000は1ビット余分なので、対応表では10000と記したが、コンピュータ上では最上位の1が切り捨てられて0000となる。

2種類の補数

補数には2種類がある。桁上がりを起こすのに必要な最小の数としての補数と、桁上がりを起こさないで済む最大の数としての補数。10進法であるならば前者が10の補数のことで後者が9の補数のこと。2進法であるならば前者が2の補数のことで後者が1の補数のこと。

桁上がりを起こす補数
10進法では10の補数
2進法では2の補数
桁上がりを起こさない補数
10進法では9の補数
2進法では1の補数

桁上がりを起こす補数

桁上がりを起こす補数(10の補数と2の補数)を求める公式がある。ある自然数xの基数がr、すなわちそれがr進法だとして、その自然数xの桁数がdだとすると、桁上がりを起こす補数yは次の公式によって計算することができる。

\[ y = r^d - x \]

この公式によって10進数である76543に対して10の補数を計算してみる。10進数であるので基数は10、76543は5桁なので10の5乗として計算することができる。

\[ \begin{align*} y &= 10^5 - 76543 \\ &= 100000 - 76543 \\ &= 23457 \end{align*} \]

Python3を起動して答え合わせ。Python3では累乗を**で表わす。

>>> r = 10
>>> d = 5
>>> x = 76543
>>> y = r**d - x
>>> y
23457

答えが一致した。

今度は2進数の10011に対する1の補数をこの公式を使って計算してみる。2進数であるので基数は2、10011は5桁なので2の5乗として計算することができる。

しかし、このままだと10進数から2進数を引く計算になってややこしい。

\[ (2^5)_{10} - (10011)_2 \]

そこで基数の2を2進数の10(イチゼロ)にあらかじめ変換しておく。そしてその5乗は0が5個あると見なせばいい。これで2進数同士の引き算ができる。

\[ \begin{align*} 10^5 - 10011 &= 100000 - 10011 \\ &= 1101 \end{align*} \] \[ \begin{eqnarray} &1&0&0&0&0&0 \\ -&&1&0&0&1&1 \\ \hline &&0&1&1&0&1 \end{eqnarray} \]

Python3で答え合わせ。int()函数は2進数を10進数に変換してくれる。bin()函数は10進数を2進数に変換してくれる。

>>> r = int("0b10",2)
>>> x = int("0b10011",2)
>>> d = 5
>>> y = r**d - x
>>> bin(y)
'0b1101'

答えは1101で一致した。

2進数の四則演算については次の記事を参照。

桁上がりを起こさない補数

桁上がりを起こさない補数(9の補数と1の補数)であるyを求める公式は次のようになる。ある自然数xの基数がr、すなわちそれがr進法だとして、その自然数xの桁数がdだとする。

\[ y = (r^d - 1) - x \]

この公式で10進数である76543に対して9の補数を計算してみる。10進数であるので基数は10、76543は5桁なので10の5乗として計算することができる。

\[ \begin{align*} (10^5 - 1) - 76543 &= (10000 - 1) - 76543 \\ &= 99999 - 76543 \\ &= 23456 \end{align*} \]

Python3で答え合わせをしてみる。

>>> r = 10
>>> d = 5
>>> x = 76543
>>> y = (r**d - 1) - x
>>> y
23456

答えは23456で一致した。そしてこの23456に1を足すと10の補数になることが分かる。

2進数の10011に対する2の補数をこの公式を使って計算してみる。2進数だから基数は2で、10011は5桁だから2の5乗となるが、このままでは10進数なので2進数に変換する必要がある。基数の2を10(イチゼロ)とし、その5乗を100000として計算すればいいだろう。

\[ \begin{align*} (10^5 - 1) - 10011 &= (100000 - 1) - 10011 \\ &= 11111 - 10011 \\ &= 1100 \end{align*} \] \[ \begin{eqnarray} &1&1&1&1&1 \\ -&1&0&0&1&1 \\ \hline &0&1&1&0&0 \end{eqnarray} \]

Python3で答え合わせをしてみる。

>>> r = int("0b10",2)
>>> x = int("0b10011",2)
>>> d = 5
>>> y = (r**d - 1) - x
>>> bin(y)
'0b1100'

補数には、コンピュータ上でNOTゲート(0を1に1を0に切り替える論理回路)を通して引き算を足し算として計算することができる利便性の他に、整数すなわち正負の数を符号用の桁(符号ビット)を設けずに表わすことができる利便性がある。それは補数法と言われているが、それについてはまたの機会に。

R言語の公式ホームページ
https://www.r-project.org/

関連記事

コメント

このブログの人気の投稿

Visual Studio 2019にはC++のためのフォームデザイナーがない件

LibreOffice 6 Calcでフォーム(ダイアログ)を作成してマクロで表示