基本情報技術者試験頻出の計算問題まとめ

基本情報技術者試験の過去問を勉強していると、何度も同じパターンの問題に巡り合います。しかし、一度出会った問題でもなかなか解き方を覚えられないことがあります。過去問を順々に解いていく方法で勉強を進めると、特に計算問題やまとめて覚える必要のある項目を一度解いても、次回の過去問を解くまでにやり方を忘れてしまうことが多いのではないでしょうか。

このような場合は同じパターンの問題をまとめて一気にさらう方が効率が良いと感じました。今回は基本情報午前問題の一番初めに出てくる計算問題のパターンを整理して覚えていきたいと思います。

数年分の過去問を参考に、今回は計算問題にて押さえておくべき項目から以下3種類を取り上げました。

- 基数変換
- 補数
- シフト演算

今回の整理で例として扱う問題は[基本情報技術者試験ドットコムさんのサイト](https://www.fe-siken.com/)に掲載されているものを引用させていただいております。

# 1.基数変換

「◯◯進数の数を〇〇進数に変換してください」という問題が、基数変換の問題です。
最初の計算問題で最もよく見かけるパターンの一つが、基数変換なのではないかと思います。

10進数の分数や小数を〇〇進数に変換させるパターンが多いようです。
以下の例題を見てみましょう。

###10進数の演算式7÷32の結果を2進数で表したものはどれか。
**ア　0.001011**
**イ　0.001101**
**ウ　0.00111**
**エ　0.0111**
（[基本情報技術者平成27年秋期 午前問1](https://www.fe-siken.com/kakomon/27_aki/q1.html)の問題より引用）


このパターンの問題は以下の３手順で解いていきます。
①10進数を小数に直す
②出てきた小数に２をかけ、その積に続けて２をかけていく
③小数部分が0になったら、それまでの掛け算の1の位を並べて解とする

###①10進数を小数に直す
まず変換元の10進数を小数に直してから計算します。
7÷32=0.21875

###②出てきた小数に２をかけ、その積に続けて２をかけていく
0.21875×2=0.4375　（1の位は0）
0.4375×2=0.875　（1の位は0）
0.875×2=1.75　（1の位は1）
0.75×2=1.5　（1の位は1）
0.5×2=1.0　（1の位は1、小数部分が0になったため終了）

###③小数部分が0になったら、それまでの掛け算の1の位を並べて解とする
1より小さい小数であるため、最終的な解の1の位は必ず0となります。
②で出していった1の位の数を小数第一位から順に並べると以下のようになります。

```
0.00111（本問ではウが答え）
```

これで２進数への変換が完了します。10進数で考えればわかりやすいですが、小数部分の一番小さい位の数字は必ず1となることに注意しましょう。

ちなみに「47.375を２進数に直しなさい」という問題のように、整数部分が1以上の場合は、47と0.375に分解して計算し、最終的な解を合計します。

整数部分の基数変換は以下の手順で行うことができます。

①与えられた数を２で割る
②その商を続けて２で割っていき、それぞれの除算の余りを下から順に並べていく

実際に解いてみます。

###①与えられた数を２で割り、その商も続けて２で割っていく
47÷2=23あまり1
23÷2=11あまり1
11÷2=5あまり1
5÷2=2あまり1
2÷2=1あまり0
1÷2=0あまり1

###②商が0になったら、それぞれの除算の余りを下から順に並べていく
最後に出てきたあまりから順に並べていくため「1÷2=0あまり1」の1が一番上の位となります。
というわけで47の2進数は「101111」になります。

この解に前述の方法で基数変換した0.375（２進数で0.011になります）を足して、「101111.011」が最終的な解となります。

今回は2進数への変換でしたが、もし2以外の基数に変換する場合は、2をかけていた部分、2で割っていた部分をその基数に置き換えて計算します。



# 2.補数

補数とは、与えられた数に足すことで位が1桁繰り上がる時の最小の数を表します。

[こちらのサイト](https://proengineer.internous.co.jp/content/columnfeature/6254)の説明がわかりやすいです。例えば321に679を足すと1000となり、位が1桁繰り上がります。この場合679は321の補数であると言います（10進数の場合、10の補数と呼びます）。

この補数を使用することで、引き算を行わず、足し算だけで引き算の結果をもたらすことができます。対象となる数から引くのではなく、引こうとしていた数の補数を足し、最上位の1を取り払うことで望んだ計算結果が得られます。

例えば「6645-567」を、補数を用いて計算します。この場合は最大4桁の数（6645）が使われているので、10000を基準とした補数を考えて計算していきます。
567の補数は9433です。6645に9433を足すと16078となります。
このままでは、元々は引き算であるにもかかわらず補数を足して位が上がってしまっているため、最上位の数を取り払います（一万の位の1）。最終的に残った「6078」が解となります。

さて、基本情報の問題でよく出てくる補数は、2進数についての1の補数と2の補数です。

2進数についての1の補数と2の補数についても[前述のこちらのサイト](https://proengineer.internous.co.jp/content/columnfeature/6254)でわかりやすい説明がなされています。

2進数の1の補数は、足し合わせて位が上がる直前の数という認識です。2進数の場合は1の補数が導きやすく、全ての桁の値を反転させることで求めることができます。（2進数00101010の補数は11010101）

2の補数というのは、1の補数に1を足した数のことを指します。すなわち、足し合わせることでちょうど位が上がる数のことです。これはつまり前述の10進数で解説していた10の補数のことになります。
2進数だけではなく、他の基数の数にもnの基数とn-1の基数が存在します。10進数にも同じ考え方で10の補数と9の補数があります。

ここで一つ、補数を用いた過去問を見てみましょう。

###ある整数値を，負数を2の補数で表現する2進表記法で表すと最下位2ビットは"11"であった。10進表記法の下で，その整数値を4で割ったときの余りに関する記述として，適切なものはどれか。ここで，除算の商は，絶対値の小数点以下を切り捨てるものとする。
**ア　その整数値が正ならば3**
**イ　その整数値が負ならば－3**
**ウ　その整数値が負ならば3**
**エ　その整数値の正負にかかわらず0**
（[基本情報技術者平成30年春期 午前問1](https://www.fe-siken.com/kakomon/30_haru/q1.html)より引用）

この問題ではまず「負数を2の補数で表現する2進表記法」について確認する必要がありそうです。[こちらのサイト](http://zaq.g1.xrea.com/2sinsuu8.htm)を参考にしました。

コンピュータで扱う2進数では負の数を表すために−の符号を使うことができないため、補数を使って負の数を表現します。
まず8ビットすなわち8桁の2進数の場合、+と-の記号を表現するために最左端のビットを符号ビットとして扱うことにします。符号ビットが1である場合負の数、0である場合正の数であることになります。

このルールのもと、10進数の33と-33を8ビットの2進数で表すと以下のようになります。

```
33 ->  00100001
-33 -> 11011111
```

この場合-33を表現している部分で補数が使われています。
以下の2手順で、正の数の負数を2の補数で表現しています。

①符号ビットを一度取り払う
②全ての位を2の補数にする
③変換後の符号ビットをつける

###①符号ビットを一度取り払う
33の2進数である「00100001」から符号ビットを取り払い、「0100001」とします。

###②全ての位を2の補数にする
「0100001」の全ての位を反転させ（1011110）1を加えることで、2の補数として「1011111」が得られます。

###③変換後の符号ビットをつける
負数に変換したいため、負の数を表す1を先頭につけて「11011111」が得られます。

さて、ここで補数を用いた過去問の内容に戻りましょう。この問題では、正か負かわからず、末尾が「11」で終わる数について、4で割るとどんな余りが出るか、ということが聞かれています。

このような問題では具体的な数で考えてみましょう。
先述の通り-33は「11011111」と表記されるため、問題の想定する数の一つとできます。さらに正の数として、35の2進数である「00100011」を想定してみましょう。それぞれの数の10進数を4で割ってみます。

```
-33÷4= -8あまり-1
35÷4= 8あまり3
```

末尾が「11」で終わる他の数について考えてみても、正の数の場合はあまり3、負の数の場合はあまり-1となります。この結果をもとに選択肢を見てみると、アが正解であることがわかります。



# 3.シフト演算

シフト演算は、桁を右や左にずらして計算する方法で、2進数の計算をするコンピュータの世界で重要な計算方法です。シフト演算については論理シフトと算術シフトの二種類があります。論理シフトと算術シフトの理解については、[こちらのサイト](https://medium-company.com/%E3%82%B7%E3%83%95%E3%83%88%E6%BC%94%E7%AE%97/)を参考にしました。

- 論理シフト

前節で扱った符号ビットを考慮せず、左右どちらかに桁をずらすシフト方法です。ずれて空いた桁には0を挿入し、溢れた数字は切り捨てます。

```
00001111
↓左に2回論理シフトする
00111100

00001111
↓右に1回論理シフトする
00000111
```

- 算術シフト

論理シフトに対して、符号ビットを考慮して演算するのが算術シフトです。左端の符号ビットを固定し、8ビットの2進数の場合は残りの7桁について論理シフトと同じ形での桁ずらしを行います。ただし符号ビットを考慮している特性上、右に算術シフトして空いた桁には符号ビットと同じ数を入れます。

```
10001111
↓左に2回算術シフトする
10111100

10001111
↓右に1回算術シフトする
11000111
```

なお左算術シフトの場合は、符号ビットと異なる数字が溢れると表現できる値の範疇を超えてしまうため、オーバーフローが発生します。

これを踏まえて基本情報の過去問を2パターン見てみましょう。


###数値を2進数で表すレジスタがある。このレジスタに格納されている正の整数xを10倍する操作はどれか。ここで，桁あふれは，起こらないものとする。
**ア　xを2ビット左にシフトした値にxを加算し，更に1ビット左にシフトする。**
**イ　xを2ビット左にシフトした値にxを加算し，更に2ビット左にシフトする。**
**ウ　xを3ビット左にシフトした値と，xを2ビット左にシフトした値を加算する。**
**エ　xを3ビット左にシフトした値にxを加算し，更に1ビット左にシフトする。**
（[基本情報技術者平成29年秋期 午前問1](https://www.fe-siken.com/kakomon/29_aki/q1.html)より引用）

2進数を左にシフトすると全ての桁が1つ繰り上がるため、元の数の2倍になります。逆に右にシフトすると全ての桁が1つ繰り下がるため、元の数の1/2倍になります。この性質を利用し、元のxが10倍の10xになる操作を見つけます。

- ア　まず2ビット左にシフトするので、元のxが2の2乗倍になり、4xが得られます。4xにxを加算するので5xとなります。最後に1ビット左シフトすることで2倍となり、10xが得られます。
- イ　まず2ビット左にシフトするので、元のxが2の2乗倍になり、4xが得られます。4xにxを加算するので5xとなります。最後に2ビット左シフトすることで2の2乗倍となり、20xが得られます。
- ウ　まず3ビット左にシフトするので、元のxが2の3乗倍になり、8xが得られます。xを2ビット左にシフトして得られた2の2乗倍の4xを足し合わせることで、12xが得られます。
- エ　まず3ビット左にシフトするので、元のxが2の3乗倍になり、8xが得られます。8xにxを加算するので9xとなります。最後に1ビット左シフトすることで2倍となり、18xが得られます。

ということで答えはアになります。具体的に桁をシフトする操作はしないものの、シフト演算の特性が問われる問題でした。もう一問だけ過去問を確認してみましょう。

###8ビットの2進数11010000を右に2ビット算術シフトしたものを，00010100から減じた値はどれか。ここで，負の数は2の補数表現によるものとする。
**ア　00001000**
**イ　00011111**
**ウ　00100000**
**エ　11100000**
（[基本情報技術者平成24年秋期 午前問1](https://www.fe-siken.com/kakomon/24_aki/q1.html)より引用）

まずは与えられた2進数を右に2ビット算術シフトし、10進数に直します。得られた数と00010100の10進数とで減算を行って、最後に2進数に直します。
負の2進数が絡んでくる計算を2進数のまま行おうとするとミスしやすいため、個人的には一度10進数に直してから計算することをお勧めします。

与えられた2進数を右に2ビット算術シフトすると以下になります。

```
11010000
↓
11110100
```

得られた「11110100」は負の数であるため、絶対値を10進数で表現して負の符号をつけます。

```
11110100
↓（符号ビットを取り払い、各桁の数を反転させ、1を加え、反転した符号を戻す）
00001100
```

得られた「00001100」は10進数で12ですので、設問で与えられた2進数を右に2ビット算術シフトした「11110100」は「-12」です

もう一つの演算対象である「00010100」は正の数であるため、そのまま「20」であることがわかります。
設問の指示通りに20-(-12)を行い、得られた32を2進数に直すと「00100000」となります。そのため答えはウになります。



# 4.最後に
今回は計算問題のパターンをいくつかピンポイントにまとめてみました。基本情報技術者試験は出題範囲が広いこともあり、項目ごとピンポイントに勉強していかないとなかなか覚えられない部分があります。戦略を考えて効率的に勉強を進めることが大事であるようです。




引用記事：
[基本情報技術者平成27年秋期 午前問1](https://www.fe-siken.com/kakomon/27_aki/q1.html)
[基本情報技術者平成30年春期 午前問1](https://www.fe-siken.com/kakomon/30_haru/q1.html)
[基本情報技術者平成29年秋期 午前問1](https://www.fe-siken.com/kakomon/29_aki/q1.html)
[基本情報技術者平成24年秋期 午前問1](https://www.fe-siken.com/kakomon/24_aki/q1.html)

参考記事：
[基本情報技術者試験ドットコム](https://www.fe-siken.com/)
[小数を含む2進数](https://mathwords.net/syosuu2sin http://www.atmarksol.jp/tech/%E5%B0%8F%E6%95%B0%E3%82%92%E5%90%AB%E3%82%802%E9%80%B2%E6%95%B0/)
[補数表現とは？１の補数と２の補数の違いと計算方法まとめ](https://proengineer.internous.co.jp/content/columnfeature/6254)
[負の数（マイナスの数）は「補数」表現で](http://zaq.g1.xrea.com/2sinsuu8.htm)
[シフト演算を分かりやすく解説](https://medium-company.com/%E3%82%B7%E3%83%95%E3%83%88%E6%BC%94%E7%AE%97/)