2進数には、桁をずらすだけで掛け算・割り算になるという性質があります。 これがシフト演算です。もうひとつ、コンピュータの計算には決まった桁数しか持てないことから来るずれがあります。 この回では、シフトの2種類と、誤差の4つの名前を扱います。
出典:基本情報技術者試験 シラバス Ver9.2 大分類1 基礎理論/中分類1 基礎理論/1. 離散数学
(3)算術演算と精度
加減乗除,表現可能な数値の範囲,シフト演算,演算精度(誤差とその対策)など,コンピュータにおける算術演算を理解する。
用語例
論理シフト,算術シフト,桁落ち,情報落ち,オーバーフロー(あふれ),アンダーフロー,単精度,倍精度
左へずらすと2倍、右へずらすと2分の1
10進数で 12 の右に 0 を1つ足すと 120 になり、10倍です。 2進数で同じことをすると、2倍になります。位が1つ左へ動くと重みが2倍になるからです(1-1 で確かめました)。
元の数 0000 1100 12 左へ1桁 0001 1000 24 ← 2倍 左へ2桁 0011 0000 48 ← 4倍
右側の空いた桁には 0 を入れます。左へ n 桁ずらすと 2 の n 乗倍です。
右へずらすと逆に、2分の1になります。
元の数 0000 1100 12 右へ1桁 0000 0110 6 ← 2分の1 右へ2桁 0000 0011 3 ← 4分の1 右へ3桁 0000 0001 1 ← 1.5 ではなく 1
右へ3桁ずらすと、はみ出した 1 は捨てられます。小数点以下は消えるので、1.5 にはなりません。
はみ出した桁は消えるので、割り切れないときは切り捨てになります。 整数どうしの割り算で小数点以下が落ちるのと同じです。
練習
8ビットの 0000 1010 を、左へ2桁シフトするとどうなりますか。
論理シフトと算術シフト ── 空いた桁に何を入れるか
ずらすと、端に桁が空きます。そこに何を入れるかで2種類に分かれます。
2種類のシフト
論理シフト … 空いた桁に必ず 0 を入れる。符号を考えない(数ではなくビットの並びとして扱う)
算術シフト … 符号ビット(いちばん左の桁。0 なら正、1 なら負)を保ち、右シフトで空いた桁には符号と同じ値を入れる
正の数ならどちらも同じ結果になります。違いが出るのは負の数を右へずらすときです。 1-2 で作った −12(1111 0100)で見ます。
元の数(−12) 1111 0100 論理シフト 0111 1010 ← 左を 0 で埋めた = 122(正の数になってしまう) 算術シフト 1111 1010 ← 左を 1 で埋めた = −6(2分の1で正しい)
どちらも右へ1桁ずらしています。符号を保つのが算術シフトです。
⚠️ 左へずらすときは、どちらも右端に 0 を入れます。 算術シフトでも符号ビットは動かさず、あふれた桁は捨てます。負の数を2倍にして桁があふれると、 正しい値になりません(この回の最後のオーバーフローです)。
論理シフトの結果 0111 1010 は、左端が 0 なので正の数です。 −12 の半分は −6 のはずなのに、122 になってしまいました。 負の数を2分の1にしたいときは、算術シフトを使います。
練習
8ビットの2の補数 1111 1100 を、算術シフトで右へ1桁ずらすとどうなりますか。
桁数が決まっているから、ずれる
ここからは誤差です。原因はどれも同じで、コンピュータが決まった桁数しか持てないことです。 名前が4つあり、いつ起きるかで見分けます。
| 名前 | いつ起きるか | 結果どうなるか |
|---|---|---|
| 桁落ち | 近い大きさの数どうしを引く | 意味のある桁が減り、以降の計算の精度が落ちる |
| 情報落ち | 大きさの離れた数を足し引きする | 小さいほうが仮数の枠に入らず、無かったことになる |
| オーバーフロー | 計算結果が、表せる最大より大きくなる | あふれた桁が捨てられ、127 + 1 が −128 のように回り込む |
| アンダーフロー | 計算結果が、表せる絶対値の最小より 0 に近づく | 0 として扱われる |
紛らわしいのは最初の2つなので、実際の計算で見ます。どちらも、仮数を8桁しか持てない場合の話です (仮数は 1-2 で出てきた「数字の並び」のほうです)。
桁落ち ── 引き算で、意味のある桁が減る
1.000 000 3 × 10⁰ − 1.000 000 0 × 10⁰ ─────────────────── 0.000 000 3 × 10⁰ → 3.000 000 0 × 10⁻⁷
8桁で持っていた数どうしの引き算ですが、残った意味のある桁は 3 の1桁だけです。下の 7 桁は、元の数が持っていなかった値で埋まります。
引いた答え 0.000 000 3 を、先頭が1桁の数になる形に直すと 3.000 000 0 × 10⁻⁷ です (小数点を右へ7つ動かしたので、指数を 7 減らしました)。
この 3.000 000 0 × 10⁻⁷ は、8桁あるように見えます。 けれども本当に意味があるのは先頭の 3 だけで、あとの 0 は計算で作られた見せかけです。 引く前は8桁ぶんの精度があったのに、引いたあとは1桁になりました。
情報落ち ── 足し算で、小さいほうが消える
1.000 000 0 × 10⁸ + 1.000 000 0 × 10⁰ ← 指数をそろえると 0.000 000 01 × 10⁸ ← 8桁の枠から、はみ出す ─────────────────── 1.000 000 0 × 10⁸ ← 足した 1 が残らない
大きいほうの仮数8桁のうち、最下位が表すのは 10 の位です(1.000 000 0 × 10⁸ = 100 000 000)。足す 1 はそのさらに下なので、入る枠がありません。
近いか離れているかの境目は、2つの数の差が仮数の桁数に収まるかです。8桁しか持てないなら、9桁ぶん離れた数は足しても引いても消えます。
あふれる方向と、0 に近づく方向
残り2つは、表せる範囲からはみ出す誤差です。
8ビットの2の補数で表せるのは −128 〜 127 でした(1-2)。ここで 127 に 1 を足します。
0111 1111 127 + 0000 0001 1 ───────── 1000 0000 ← 左端が 1 になった = −128
8ビットで表せるのは −128 〜 127。127 の次は、いちばん小さい −128 に回り込みます。
これがオーバーフローです。
逆に、0 に近づきすぎて表せなくなるのがアンダーフローです。 浮動小数点数では指数にも桁数の限りがあるので、非常に小さい値は 0 とみなされます。
誤差の見分け方
- まず、2つの数の大きさを比べる。けた違いに離れていれば情報落ちです。足し算でも引き算でも起きます。
- 近い大きさどうしなら、引き算かを見る。近い数の引き算で上の桁が打ち消し合うと桁落ちです。足し算では起きません。
- 答えが表せる範囲に収まるかを見る。最大を超えたらオーバーフロー、0 に近づきすぎて表せなくなったらアンダーフローです。
対策も裏返しです。桁落ちは式を変形して、近い数どうしの引き算そのものを避ける。 情報落ちは小さい数どうしから先に足す。あふれは桁数の多い形式(1-2 で出てきた倍精度)を使うのが基本です。
先に、ひとつ予想してみましょう
仮数を8桁しか持てない計算機で 1.234 567 8 × 10⁶ + 9.876 543 2 × 10⁻³ を計算しました。このとき起きるのはどれですか。
まとめ
この回で持ち帰ること
1. 2進数を左へ n 桁ずらすと 2 の n 乗倍、右へ n 桁で 2 の n 乗分の1。はみ出した桁は消える
2. 論理シフトは空いた桁に 0。算術シフトは符号を保ち、右シフトでは符号と同じ値を入れる
3. 桁落ちは近い数の引き算、情報落ちは離れた数の足し算
4. 範囲から出るのがオーバーフロー、0 に近づきすぎるのがアンダーフロー
次に読む
この記事で引用した資料
いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。
本文の例(00001100 のシフト、0.1+0.2、1.0×10⁸ + 1 などの桁数の話)と練習問題は、すべて当サイトが説明のために作ったものです。

