% 1001 ÷ 11,余りはいくつ?(計算機での話)
\documentclass[dvipdfmx]{jsarticle}
\pagestyle{myheadings}
\markright{tmt's math page}
\def\baselinestretch{1.33}
\begin{document}
\section*{◆$1001\div11$、余りはいくつ?(計算機での話)◆}
「$(-7)\div3$」の余りについては、数学の自然な立場から見れば
\[
(-7)\div3 = -3、\quad 余り\ 2
\]
であるとの結論を得ました。そのついでに計算機、いわゆるコンピュータの場合について話しましょう。
コンピュータでは内部の計算を$2$進数でするのが普通です。私たちは$0$〜$9$までの$10$種類の数字を使って様々な数を表しています。これが$10$進数です。ですから$2$進数は$2$種類の数字、すなわち$0$と$1$だけを使って様々な数を表すものです。使う数字が少ないので$10$進数に比べると桁上がりが頻繁で、人間にとっては扱いづらいかもしれません。しかしコンピュータにとっては、たとえば電流が「流れた/流れない」の$2$値で判断する方が確実で正確です。もちろん$2$進数であっても$10$進数であっても、計算の規則自体はまったく同じです。
それなのになぜ同じ話題を取り上げたのかって? それはコンピュータには特殊な事情があるからです。特殊な事情の一つに、誤差の問題がありますが、ここでは負の数に関する話題に絞ります\footnote{$\displaystyle \frac{1}{5}$は$10$進数では有限小数$0.2$ですが、$2$進数では$0.00110011\dots$と無限循環小数になります。}。
まず話を簡単にするため、この章に登場するコンピュータは$4$ビットで演算を行うものとします。つまり、$4$桁の$2$進数$0000$〜$1111$だけが扱えるということです。このとき「$111\div11$」は「$7\div3$」を意味しますから、計算結果は「$111\div11 = 10$、余り$1$」となるでしょう。
ところでコンピュータが$4$ビットで演算をする場合は、$0$〜$15$までの数しか扱えないことになります。ただこのことはコンピュータにとって致命的な欠陥にはなりません。というのは、たとえ一つの変数が$4$ビット分しか使えなくても、いくつかの変数を組み合わせれば$8$ビットにでも$16$ビットにでもできるからです。これは$10$進数が変数$a$や$b$に$0$〜$9$までしか使えなくても、$10a+b$のように組み合わせれば桁数を増やせることと似ています。
コンピュータが困るのは大きい桁数の扱いではなく、負の数の扱いなのです。
そのためにコンピュータ内部では最上位の桁を符号のために使うことがあります。つまり最上位が$0$なら正の数、$1$なら負の数という仕組みです。この約束により正の数は
\begin{center}
\begin{tabular}{ccccccccc}
$2$進数 & $0000$ & $0001$ & $0010$ & $0011$ & $0100$ & $0101$ & $0110$ & $0111$ \\
$10$進数 & $0$ & $1$ & $2$ & $3$ & $4$ & $5$ & $6$ & $7$
\end{tabular}
\end{center}
の対応となり、負の数は
\begin{center}
\begin{tabular}{ccccccccc}
$2$進数 & $1000$ & $1001$ & $1010$ & $1011$ & $1100$ & $1101$ & $1110$ & $1111$ \\
$10$進数 & $-8$ & $-7$ & $-6$ & $-5$ & $-4$ & $-3$ & $-2$ & $-1$
\end{tabular}
\end{center}
になるのです。負の数は慣れないとわかりづらいでしょうが、$1000$から$1111$までは$1$ずつ増えていますし、「$1111+1 = 0000$」は「$-1+1 = 0$」を意味するわけですからこれでよいのです。
実はこのことがちょっとした混乱をもたらします。$2$進数では$0111+1 = 1000$ですから$0111$の次の数は$1000$ということになります。これを$10$進数で言えば$7$の次の数は$-8$となってしまうのです。ただ、このことは大きな問題にはなりません。なぜなら$4$ビットの$2$進数の世界では、数は$-8$〜$7$までしかないのです。だからその世界の最大数の次が、その世界の最小数になるという循環を含んでもかまわないでしょう。
混乱は四則演算をするときに発生します。私たちが普通に$2$進数を考えたとき、$111\div11$は$10$進数の$7\div3$にあたります。しかし最上位の$1$を負の符号で扱っていれば、$111\div11$は$10$進数の$(-1)\div(-1)$になってしまうかもしれません。もっとも$4$ビットのコンピュータであることが前提なら、これは$0111\div0011$ですから余計な心配は無用です。困るのは次のようなときです。
$1111\div0011$が符号を持たない$2$進数の計算であれば$15\div3$ですが、最上位の桁$1$が負の数を表す$1$であるとすれば$(-1)\div3$です。コンピュータにとって、最上位の$1$は、死活問題と呼んでいい程の重大事なのです。
そのためにコンピュータは、いま扱っている数が「符号付き数」なのか「符号なし数」なのかを、常に把握しながら計算をしているのです。それだと、計算規則が複雑になりそうに思えますが、コンピュータはこれを楽に回避しています。
コンピュータは各ビットの$0$と$1$を反転させることはお手のものです。つまり$1011$なら各ビットを反転させて$0100$とします。そして反転させた数に$1$を加えると、「符号交換」された数ができあがるのです。いくつかの具体例をあげましょう。$[~]$内の数は$10$進数を表しています。
\begin{center}
\begin{tabular}{rrrrr}
$1011$ & [$-5$] & $\to$ & $0100+1 = 0101$ & [$5$] \\
$0011$ & [$3$] & $\to$ & $1100+1 = 1101$ & [$-3$] \\
$0001$ & [$1$] & $\to$ & $1110+1 = 1111$ & [$-1$] \\
$1111$ & [$-1$] & $\to$ & $0000+1 = 0001$ & [$1$] \\
$0000$ & [$0$] & $\to$ & $1111+1 = 0000$ & [$0$]
\end{tabular}
\end{center}
するとコンピュータ内部で負の数の計算をするとき、一度各ビットを反転させて計算し、再び反転させるというやり方が成立します。「$1010\div0011$」の計算を例に説明しましょう。これは「$(-6)\div3$」の計算です。
\begin{eqnarray}
1010\div0011 &=& (0101+1)\div0011 \label{1stStep} \\
&=& 0110\div0011 \nonumber \\
&=& 0010 \nonumber \\
&=& (1101+1) \label{2ndStep} \\
&=& 1110 \nonumber
\end{eqnarray}
(\ref{1stStep})と(\ref{2ndStep})の$(~)$内がビット反転による符号交換をしているところです。きっちり「$(-6)\div3 = -2$」となりました。式にすると長ったらしい気もしますが、コンピュータ内部では「(反転)→(割り算)→(反転)」の手順を機械的に踏んでいるだけです。
ところがこの機械的な作業が次のような割り算に影響します。「$1001\div0011$」を例にとりましょう。これは「$(-7)\div3$」の計算です。
\begin{eqnarray}
1001\div0011 &=& (0110+1)\div0011 \\
&=& 0111\div0011 \nonumber \\
&=& 0010、\quad 余り\ 0001 \label{1stStep+} \\
&=& (1101+1)、\quad 余り\ (1110+1) \label{2ndStep+} \\
&=& 1110、\quad 余り\ 1111 \label{lastStep+}
\end{eqnarray}
$(~)$内が符号交換になっています。(\ref{1stStep+})で答がでたものの、これを符号交換させなくては正しい答になりません。そこで(\ref{2ndStep+})の符号交換を経て(\ref{lastStep+})になるわけですが、(\ref{lastStep+})は$10$進数では「$(-7)\div3 = -2$、余り$-1$」ということです。コンピュータにとって\.楽\-\.な計算をすることが、結果的に余りに負の数を出すことになっていたのでした。このような仕組みのために、数学の自然な感覚と違う結果---しかし日常の感覚には近い---になるのは皮肉なものです\footnote{ソフトウェアの仕様によっては「$(-7)\div3 = -3、余り\ 2$」となっています。}。
\end{document}