基本情報技術者試験問題に挑戦しよう!(2の補数)~Pythonでつくって確かめる~【GitHub対応】

GitHubでつくって学ぶ

基本情報技術者試験とは

基本情報技術者試験は、情報処理推進機構(IPA)が実施し、「情報処理の促進に関する法律」に基づき経済産業省が認定する国家試験である。

ITエンジニアとしてキャリアをスタートする方のIT基礎力を問う試験で、「ITエンジニアの登竜門」とも言われる。

科目Aと科目Bの両科目で合格点を取らなければ、基本情報技術者試験の合格とはならない。

今回は、科目Aのサンプル問題を題材に、答えを覚えるのではなく、Pythonの短いプログラムを実際に動かして理論を確かめるという進め方で解説する。

なお、この記事で使用するコードは、学習用リポジトリ pc-labo-fe-eam-python 01_2no_hosu フォルダにまとめている。
ご自分で python3 two_complement.py を実行すれば、そのまま同じ結果を確認できる。


それでは、基本情報技術者試験(科目A)のサンプル問題にチャレンジしてみよう。

サンプル問題 (科目A)問1

負数を2の補数で表すとき,8 ビットの2 進正数nに対し-n を求める式はどれか。
ここで,+は加算を表し,OR はビットごとの論理和,XOR はビットごとの排他的論理和を表す。
ア (n OR 10000000) + 00000001
イ (n OR 11111110) + 11111111
ウ (n XOR 10000000) + 11111111
エ (n XOR 11111111) + 00000001

正解:エ

2の補数表現とは

2の補数表現とは、すべてのビットを反転した後にを足して正負を表す方法である。
全ビットを反転するときに使われる論理演算が、排他的論理和(XOR)である。

排他的論理和(XOR)

AとBが異なる場合、「1」、AとBが同じ場合、「0」となる論理演算。
XOR 1 の結果は、元のビットを反転したビットとなる。

8 ビットの2 進正数n に対し-n を求めるには、
① nの全ビットを反転する → n XOR 11111111
② ①の結果に1を加算する。→ +00000001

そこで、
①と②を組み合わせた式「(n XOR 11111111) + 00000001」となる。


正解するだけならここで終わりだが、「なぜエなのか」をPythonで実際に検証してみよう。

Pythonでつくって確かめてみよう

Pythonなら数行のコードで、2進数の反転・加算をそのまま試すことができる。

以下のプログラムを、GitHubでPython が使える環境を構築して実行してみよう。
なお、GitHubについては、こちらの記事を参照してほしい。

Python(全体)

def two_complement(n: int, bits: int = 8) -> int:
    """8ビット2進正数nに対して、2の補数で-nを求める"""
    mask = (1 << bits) - 1        # 11111111(XORに使うマスク)
    inverted = n ^ mask           # ① 全ビットを反転する(XOR)
    result = inverted + 1         # ② 1を加算する
    return result & mask          # 8ビットの範囲に収める


def main():
    print("=== 2の補数を求める ===")
    for n in [1, 5, 100, 127]:
        neg_n = two_complement(n)
        print(f"n = {n:3d} (0b{n:08b})  ->  -n = {neg_n:3d} (0b{neg_n:08b})")

    print()
    print("=== n + (-n) が8ビットでは0に戻ることを確認 ===")
    for n in [1, 5, 100, 127]:
        neg_n = two_complement(n)
        total = (n + neg_n) & 0xFF  # 8ビットに収めてから確認
        print(f"n={n:3d} + (-n)={neg_n:3d}  ->  8ビットでは {total}")


if __name__ == "__main__":
    main()

実行結果

=== 2の補数を求める ===
n =   1 (0b00000001)  ->  -n = 255 (0b11111111)
n =   5 (0b00000101)  ->  -n = 251 (0b11111011)
n = 100 (0b01100100)  ->  -n = 156 (0b10011100)
n = 127 (0b01111111)  ->  -n = 129 (0b10000001)

=== n + (-n) が8ビットでは0に戻ることを確認 ===
n=  1 + (-n)=255  ->  8ビットでは 0
n=  5 + (-n)=251  ->  8ビットでは 0
n=100 + (-n)=156  ->  8ビットでは 0
n=127 + (-n)=129  ->  8ビットでは 0

inverted = n ^ mask の部分が①全ビットを反転する(XOR)に、result = inverted + 1 の部分が②1を加算するに対応している。
プログラムのコードと正解肢エの式が、そのまま1対1で対応していることが確認できる。

n + (-n) が0に戻ることも確かめる

2の補数のもう一つの性質として、「nと-nを足すと、8ビットの範囲では0に戻る(桁あふれする)」というものがある。これもコードで確かめておこう。

以下は先ほどの two_complement.py の続き(抜粋)である。
two_complement 関数はそのまま使うので、単体では動かず、先ほどのコードの下に追記する形で実行してほしい。

Python(抜粋)

# (抜粋:two_complement()関数の定義に続けて記述する)
for n in [1, 5, 100, 127]:
    neg_n = two_complement(n)
    total = (n + neg_n) & 0xFF   # 8ビットに収めてから確認
    print(f"n={n:3d} + (-n)={neg_n:3d}  ->  8ビットでは {total}")
=== n + (-n) が8ビットでは0に戻ることを確認 ===
n=  1 + (-n)=255  ->  8ビットでは 0
n=  5 + (-n)=251  ->  8ビットでは 0
n=100 + (-n)=156  ->  8ビットでは 0
n=127 + (-n)=129  ->  8ビットでは 0

どの n についても、加算結果が8ビットの範囲では必ず0になることが確認できた。
これが「2の補数を使えば、コンピュータが引き算を足し算だけで実現できる」という仕組みの正体である。

まとめ

  • 2の補数表現は「全ビット反転(XOR)」+「1を加算」で求められる
  • 正解の式「(n XOR 11111111) + 00000001」は、この2手順をそのまま表している
  • Pythonで実際に動かすと、n と -n を足した結果が8ビットの範囲で0に戻ることまで確認できる

暗記だけでなく、短いコードを1本つくって動かしてみることで、ビット演算の意味が体感として残りやすくなるだろう。

参考リポジトリ

この記事で扱ったコードは、以下のGitHubリポジトリで公開している。今後の「基本情報技術者試験問題に挑戦しよう!」シリーズのPythonコードも、同じリポジトリにフォルダを追加していく形でまとめていく予定である。

GitHub – HappyTalk10/pc-labo-fe-exam-python
Contribute to HappyTalk10/pc-labo-fe-exam-python development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました