* 符号付き整数について -(by [[K]], 2013.06.24) ** (0) はじめに -rev2でbitが出てくるようになり、この辺の挙動への知識があったほうが、VMなどの開発に有利なので解説することにしました。 -アプリ開発しかしないときは、この知識はなくても大丈夫です。というかVM開発でも細かいことを気にしなければ、この知識はなくても大丈夫です。 ** (1) 10進数で練習(足し算、引き算、掛け算) -ここにゼロもしくはプラスの数しか計算できない、しかも2桁しか表示できない、超おんぼろの計算機があったとしましょう。 --「01」+「23」=「24」 --こんな感じです。 -さてこの計算機で、「97」+「05」を計算したらどうなるでしょうか。 --「97」+「05」=「02」 -おお、なんと2になってしまいました。そうです、本当は102なのですが、二桁しか表示できないので、「02」になってしまうのです。 -これを「桁が足りなくて不十分な結果を表示している(=エラー)」とはあえて考えないで、5にある数を足したら2になった、と考えてみると、「97」は-3の代わりになっていると考えることができます。 -負の数が計算できないおんぼろ計算機でしたが、こうやって工夫することで、マイナスの数が扱えるのです。 --「99」は-1の代わり。 --「87」は-13の代わり。 --「65」は-35の代わり。 ---- -さてこの「代用」はどのくらい有効なのでしょうか。試しに、「87」と「99」を足してみましょう。 --「87」+「99」=「86」(本当は186) -ほほう、(-13)+(-1)=(-14)なので、この計算は合っています。つまり、負の数どうしを加えてもうまくいくのです。 -じゃあ引き算はどうでしょうか。-2から3を引いてみましょう。 --「98」-「03」=「95」 -これは-5なので合っています。 -では、-2から-3を引くのはどうでしょうか。 --「98」-「97」=「01」 -すごいじゃないですか。ばっちりですよ! -さらに悪乗りして、(-3)*3をやってみましょう。 --「97」*「03」=「91」(本当は291) -「91」は-9なのでこれもあっています。 -じゃあ、(-4)*(-5)は? --「96」*「95」=「20」(本当は9120) -おおー。これもあっていますね!! -でもうまくいくのはここまでです。割り算はうまくいきません。だから検算もしません。 ---- -引き算で「01」から「07」を引いたらどうなるでしょうか。おんぼろ計算機ではもちろんエラーです。エラーなのですが、とりあえず無理やり「94」が表示されます。 -この表示の根拠はこうです: --1から7は引けない。でももしかしたら1は1ではなくて101のつもりだったのかもしれない。 --ボクは2桁しか入力できない計算機だから、ご主人様は101を入力したかったけど下2桁で我慢したのかもしれない、うん、きっとそうだ。 --1から7は引けないけど、101からなら引ける。ご主人様の単なるミスかもしれないからエラー表示はするけど、でも一応101から7を引いた94も表示しておこう! -そしてこの「気の利いた対応」のおかげで、1-7=(-6)となり、符号付き整数の考え方はうまくいくことになります。 ---- -すこしテクニックを紹介しましょう。ある数があったとして、その数の符号を反転したいとします(つまり-1を掛け算するということです)。その時は以下の手順でできます。 --「99」からその数を引く。・・・これは繰り下がりのない引き算になるので超簡単。暗算もできる。 --その結果に「01」を足す。 -つまり、「12」の符号を反転したければ、99-12=87にして、+1して「88」というわけです。 -「56」の符号を反転すると、43+1=「44」というわけです。 -まあそんなことしなくても、100から引けばいいって?まあそうです。でも10進数以外では引き算の暗算は容易ではないので、繰り下がりのない引き算形式を経由する方法は、役に立つことがあります。 ---- -この符号付き整数では、最初の桁が「0~4」の場合は正の数、最初の桁が「5~9」の場合は負の数、と解釈します。 ** (2) 符号拡張(まだ10進数だけで考えています) -この2桁のおんぼろ計算機ですが、もしもう一台4桁のおんぼろ計算機があったとしたら、数値がどのように対応するでしょうか。 --「00」=「0000」 --「12」=「0012」 --「34」=「0034」 --「98」=「9998」(どちらも-2を意味する) --「76」=「9976」(どちらも-24を意味する) --「54」=「9954」(どちらも-46を意味する) -このように、補う上位2桁は、「00」だったり「99」になったりします。どちらになるかは、十のくらいが「0~4」か「5~9」なのか、ということで決まります。 -ちなみに符号なし整数では、かならず「00」を補います。これはゼロ拡張と呼ばれます。それに対して、値によって「99」だったり「00」だったりする桁拡張は「符号拡張」と呼ばれます。 ** (3) 計算の省略(まだ10進数だけで考えています) -たとえば歴史上の人物の享年(死んだ時の年齢)を調べる計算を考えます。 -たとえば織田信長は、1534年に生まれて1582年に死亡しています。 -このとき1582-1534をまじめに計算することもできますが、100歳未満だということを事前に知っていれば、下2桁だけで計算することもできます。「82」-「34」=「48」。 -この方法は世紀をまたがっても問題なくできます。徳川家康なら1616-1543ですが「16」-「43」=「73」で、ちゃんと正しい答えが出るのです。 -上位の桁がそろっているからそんなことができるんだ、と思うかもしれません。じゃあ、1から(-1)を引くことを考えましょう。答えは2になるべきです。 --4桁でやった場合:「0001」-「9999」=「0002」(10000を補うルールを使いました) --2桁でやった場合:「01」-「99」=「02」(100を補うルールを使いました) --1桁でやった場合:「1」-「9」=「2」(10を補うルールを使いました) -つまり、結果の範囲がだいたいわかっていれば、その桁数だけ取り出して、それより上の桁を全部無視しても、正しい答えが出るのです。 -これは引き算だけではなく、掛け算でも足し算でも同じ性質があります。 ** (4) ゴミの除去(まだ10進数だけで考えています) -4桁くらいの数値を10個合計し、25で割った余りがいくつになるのか知りたいとします。この時、計算をまじめにやる必要はなく、合計の際は2桁だけやっていれば十分でしょう。 -しかし計算機の都合で、4桁のまま計算してしまいました(わざわざ2桁だけを取り出す操作が面倒だったので)。さてその結果は「6543」でした。・・・ここで問題です、もしこの計算を上記の考察のとおり2桁の計算機でやっていたら、どんな結果になっていたでしょうか。そうです、「43」です。これを4桁の計算機のままで表現するのなら「0043」になります。 -この「0043」はどうすれば得られるでしょうか。そうです、上位の桁(=ゴミ)を0でつぶしてしまえばいいのです。 -符号付き整数では、ゼロ拡張ではなく符号拡張するべきなので、「6543」の「4」をみて「00」を埋めることになります。 ** (5) 2進数 -上記の議論はすべて2進数でもそのまま成立します。そしてそれが、OSECPU-VMの命令セットの根拠になっています。 * こめんと欄 #comment