コンテンツにスキップ

1-1. 演習問題


次の説明に当てはまる部品を選んでください。

1-1. プログラムを実行中に一時的にデータを保存する場所で、電源を切ると内容が消える。

  • A. CPU
  • B. メモリ(RAM)
  • C. SSD
解答と解説

正解:B. メモリ(RAM)

  • A の CPU は「計算・判断・制御」を行う処理装置であり、データの保存場所ではない。
  • B のメモリ(RAM)は、実行中のプログラムやデータを一時的に保持する。電気でデータを保持する仕組み(DRAM)のため、電源を切るとデータが消える(揮発性)。
  • C の SSD はフラッシュメモリ型のストレージで、電源を切ってもデータは消えない(不揮発性)。「一時的」かつ「電源を切ると消える」という2つの条件がRAMを指している。

1-2. 1秒間に3GHzのCPUは、何回の処理ができるか。

  • A. 3,000回
  • B. 3,000,000回
  • C. 3,000,000,000回
解答と解説

正解:C. 3,000,000,000回

G(ギガ)は「10億(10⁹)」を意味する接頭語。

3 GHz = 3 × 10⁹ Hz = 3,000,000,000 回/秒

接頭語の早見表:

接頭語読み大きさ
K(キロ)10³
M(メガ)百万10⁶
G(ギガ)十億10⁹
T(テラ)一兆10¹²

ただし「クロック1回=1命令」とは限らない。現代のCPUは1クロックで複数の命令を実行できる設計になっている(スーパースカラ)。

1-3. UTF-8で日本語の文字(例:「あ」)は何バイトで表されるか。

  • A. 1バイト
  • B. 2バイト
  • C. 3バイト
解答と解説

正解:C. 3バイト

UTF-8 は文字の種類によって使用バイト数が変わる可変長エンコーディング。

文字の範囲バイト数
ASCII文字(英数字)1バイトA, 0
ラテン文字・記号2バイトé, ñ
日本語・中国語・韓国語3バイト,
絵文字など4バイト😀

ASCIIが1バイトなのに対して日本語が3バイトになるのは、UTF-8がASCIIとの後方互換を保ちつつ、多言語文字を効率よく格納するよう設計されているため。


次の10進数を2進数に変換してください。

  1. 5
  2. 10
  3. 255
解答欄

次の2進数を10進数に変換してください。

  1. 0110
  2. 1010
  3. 11111111
解答欄
解答と解説

10進数 → 2進数(手順:2で割り続けて余りを逆順に読む)

1. 50101

5 ÷ 2 = 2 余り 1 ← 最下位ビット
2 ÷ 2 = 1 余り 0
1 ÷ 2 = 0 余り 1 ← 最上位ビット
余りを下から読む → 101(= 0101)

2. 101010

10 ÷ 2 = 5 余り 0
5 ÷ 2 = 2 余り 1
2 ÷ 2 = 1 余り 0
1 ÷ 2 = 0 余り 1
余りを下から読む → 1010

3. 25511111111

255 ÷ 2 = 127 余り 1
127 ÷ 2 = 63 余り 1
63 ÷ 2 = 31 余り 1
31 ÷ 2 = 15 余り 1
15 ÷ 2 = 7 余り 1
7 ÷ 2 = 3 余り 1
3 ÷ 2 = 1 余り 1
1 ÷ 2 = 0 余り 1
余りを下から読む → 11111111(8ビット全て1 = 1バイトの最大値)

2進数 → 10進数(手順:右から2の0乗、2の1乗…と掛けて合計する)

4. 01106

桁の重み: 2³ 2² 2¹ 2⁰
8 4 2 1
値: 0 1 1 0
計算:0×8 + 1×4 + 1×2 + 0×1 = 0 + 4 + 2 + 0 = 6

5. 101010

桁の重み: 2³ 2² 2¹ 2⁰
8 4 2 1
値: 1 0 1 0
計算:1×8 + 0×4 + 1×2 + 0×1 = 8 + 0 + 2 + 0 = 10

6. 11111111255

桁の重み:128 64 32 16 8 4 2 1
値: 1 1 1 1 1 1 1 1
計算:128+64+32+16+8+4+2+1 = 255
覚え方:2⁸ - 1 = 256 - 1 = 255(8ビット全1の最大値)

次の16進数を10進数に変換してください。

  1. 0x0A
  2. 0xFF
  3. 0x1F
解答欄

次の10進数を16進数に変換してください。

  1. 16
  2. 255
  3. 100
解答欄
解答と解説

16進数 → 10進数(手順:右から16の0乗、16の1乗…と掛けて合計する)

1. 0x0A10

0x0A の各桁:0, A(AはF系で10を意味する)
計算:0×16¹ + 10×16⁰ = 0 + 10 = 10
補足:0x はプログラムで「これは16進数」と示す接頭辞(値そのものではない)

2. 0xFF255

F = 15(16進数の最大値)
計算:15×16¹ + 15×16⁰ = 240 + 15 = 255
補足:0xFF は1バイト(8ビット)で表せる最大値。
2進数で 11111111、10進数で 255 はセットで覚えると役立つ。

3. 0x1F31

計算:1×16¹ + 15×16⁰ = 16 + 15 = 31

10進数 → 16進数(手順:16で割り続けて余りを逆順に読む)

4. 160x10

16 ÷ 16 = 1 余り 0
1 ÷ 16 = 0 余り 1
余りを下から読む → 10(= 0x10)
ポイント:16進数の桁が1つ増えるのは10進数の16の倍数のとき(10進数と同じ仕組み)

5. 2550xFF

255 ÷ 16 = 15 余り 15 → F
15 ÷ 16 = 0 余り 15 → F
余りを下から読む → FF(= 0xFF)

6. 1000x64

100 ÷ 16 = 6 余り 4
6 ÷ 16 = 0 余り 6
余りを下から読む → 64(= 0x64)

4-1. HDDとSSDの違いを2点以上挙げて説明してください。

解答欄
解答と解説

4-1. HDDとSSDの違い

比較項目HDDSSD
記録方式磁気ディスク(回転する円盤に磁気で書き込む)フラッシュメモリ(電気的にデータを保持)
速度遅い(ディスクの回転とヘッドの移動が必要)速い(物理的な可動部品がない)
耐衝撃性弱い(衝撃で読み書きヘッドが損傷しやすい)強い(可動部品がないため)
価格同容量で安い同容量でやや高い(近年は低下傾向)
騒音あり(ディスクの回転音)なし

なぜエンジニアがこれを知る必要があるか? 本番サーバーのストレージ選定やパフォーマンス問題の調査で知識が役立つ。データベースのようなランダムアクセスが多い用途ではSSDが有利。

4-2. OSがなければ、アプリケーション開発者はどのような問題に直面するか?具体的に1つ説明してください。

解答欄
解答と解説

4-2. OSがなければ直面する問題(例)

OSがなければ開発者はハードウェアを直接制御しなければならない。

例として、ファイルに書き込む処理を考える。OSがある場合:

file.write("hello") ← 1行でOSに任せられる

OSがない場合、開発者は以下を自前で実装する必要がある:

  • ディスクのどのセクタ・シリンダに書き込むか
  • メーカー固有のディスクコントローラへの命令
  • 複数のプログラムが同時にディスクを使おうとしたときの競合制御

OSはこうした低レベルの処理を隠蔽(抽象化)してくれることで、開発者はアプリのロジックに集中できる。

4-3. 文字化けはなぜ起きるのか、自分の言葉で説明してください。

解答欄
解答と解説

4-3. 文字化けの原因

文字コードとは「数値と文字の対応表」のこと。送り手と受け手が異なる対応表を使うと、同じ数値でも別の文字として解釈される。

例:Shift-JIS と UTF-8 の違い

送信側(Shift-JIS): 「あ」→ 0x82A0 として送信
受信側(UTF-8) : 0x82A0 → 「あ」という文字は存在しない → 文字化け

対策:送受信の両端で文字コードを統一する(現代のWebでは UTF-8 が標準)。


以下の状況で、ボトルネック(最も遅い原因)はどこにあると考えられるか答えてください。

状況: 大量のCSVファイルを読み込んで集計するプログラムが遅い。CPUの使用率は30%しかない。

解答欄
解答と解説

ボトルネック:ストレージ(I/O)

根拠となる観察 CPUの使用率が30%しかないということは、CPUは仕事を待っている時間が多い状態を示している。CPUが待つ原因として最も多いのは「データの読み込みが終わるのを待っている」状態(I/O待ち)。

[プログラムの動き]
CSVを読み込む(ストレージへアクセス)
↓ ← ここで待っている(CPUはアイドル状態)
データが届く
計算する(CPUを使うが、量が少なく30%で済む)
また次のCSVを読み込む → 繰り返し

改善策

対策効果
HDD → SSD に交換ディスクアクセス速度が大幅に向上
ファイルをまとめて読む(バッファリング)ディスクへのアクセス回数を減らす
複数ファイルを並列で読む(マルチスレッド)I/O待ちの間に別のファイルを読める

このように「CPUが遅い」と「I/Oが遅い」では対策が全く異なるため、ボトルネックの特定(プロファイリング)がパフォーマンス改善の第一歩になる。


実際に手元で確認してみましょう。

① 2進数と16進数を確かめる

次のコマンドを実行し、131101255FF と表示されることを確認する。

Terminal window
node -e "console.log((13).toString(2)); console.log((255).toString(16).toUpperCase())"

② UTF-8 のバイト数を確かめる

次のコマンドを実行し、A1 バイト、3 バイト、😀4 バイトと表示されることを確認する。

Terminal window
node -e "console.log(Buffer.byteLength('A', 'utf8')); console.log(Buffer.byteLength('あ', 'utf8')); console.log(Buffer.byteLength(String.fromCodePoint(0x1F600), 'utf8'))"

③ PC の資源を観察する

タスクマネージャーを開き、VS Code やブラウザを起動したときに CPU メモリ ディスク のどれが変化するか観察する。

解答と解説

① 2進数と16進数を確かめる

Terminal window
$ node -e "console.log((13).toString(2)); console.log((255).toString(16).toUpperCase())"
1101
FF

toString(2) は数値を2進数文字列に、toString(16) は16進数文字列に変換する。 講義で学んだ変換が、実際にコンピュータ上でも同じ規則で扱われていると確かめられる。


② UTF-8 のバイト数を確かめる

Terminal window
$ node -e "console.log(Buffer.byteLength('A', 'utf8')); console.log(Buffer.byteLength('あ', 'utf8')); console.log(Buffer.byteLength(String.fromCodePoint(0x1F600), 'utf8'))"
1
3
4

Buffer.byteLength() は、文字列がUTF-8で何バイト必要かを調べる関数である。 これにより、ASCII文字は1バイト、日本語は3バイト、絵文字は4バイトになることを実測できる。 「文字数」と「バイト数」は同じではない、という点が実務でも重要である。


③ PC の資源を観察する

たとえばアプリ起動直後は CPU 使用率が一時的に上がり、起動後はメモリ使用量が増えることが多い。 大きなファイルを開くとディスク使用量が増えることもある。 ここで大切なのは正確な数値を覚えることではなく、CPU・メモリ・ストレージはそれぞれ別の役割を持ち、観察の仕方も違う と理解することである。


7-1. 0b1100 & 0b1010 の結果はどれか。

  • A. 0b1110
  • B. 0b1000
  • C. 0b0110
解答と解説

正解:B. 0b1000

AND は対応するビットが両方とも1のときだけ1になる。

1100
& 1010
------
1000 ← 上から3ビット目だけ両方1

A の 1110 は OR の結果。C の 0110 は XOR の結果。混同しないよう注意。

7-2. 0b1100 | 0b1010 の結果はどれか。

  • A. 0b1110
  • B. 0b1000
  • C. 0b0110
解答と解説

正解:A. 0b1110

OR は対応するビットのどちらか一方が1なら1になる。

1100
| 1010
------
1110 ← 下1ビット目だけ両方0なので0、それ以外は1

7-3. 左シフト 1 << 4 の結果はどれか。

  • A. 4
  • B. 8
  • C. 16
解答と解説

正解:C. 16

左シフト << n は 2ⁿ 倍と同じ効果。

1 << 4 = 1 × 2⁴ = 1 × 16 = 16

A の 41 << 2 の結果。B の 81 << 3 の結果。

7-4. ビット演算 AND がよく使われる用途はどれか。

  • A. 特定のビットを取り出す(マスク処理)
  • B. 特定のビットを立てる(フラグのセット)
  • C. ビットを左右にずらして2の累乗倍を計算する
解答と解説

正解:A. 特定のビットを取り出す(マスク処理)

  • A(AND):抽出したいビット位置を1にしたマスクと AND を取ると、そのビットだけを取り出せる(マスク処理)。
  • B(OR):特定のビットを1にセットするのは OR が使われる。
  • C(シフト演算):2の累乗倍の計算は << / >> の用途。

次のビット演算の結果を2進数と10進数で答えてください。

  1. 0b00001111 & 0b10110111
  2. 0b00000000 | 0b00000010
  3. 0b1010 ^ 0b1100
解答欄

次のシフト演算の結果を10進数で答えてください。

  1. 3 << 2
  2. 32 >> 3
  3. 1 << 8
解答欄
解答と解説

1. 0b00001111 & 0b10110111

00001111
& 10110111
----------
00000111 → 2進数: 0000 0111 / 10進数: 7
ポイント:マスク 0b00001111 との AND で下4ビットだけを取り出している。

2. 0b00000000 | 0b00000010

00000000
| 00000010
----------
00000010 → 2進数: 0000 0010 / 10進数: 2
ポイント:0 との OR はもとの値がそのまま残る。
「フラグを立てる」操作の典型例。

3. 0b1010 ^ 0b1100

1010
^ 1100
------
0110 → 2進数: 0110 / 10進数: 6
ポイント:同じビットは0、異なるビットは1になる。

4. 3 << 2

3 × 2² = 3 × 4 = 12
ビット:0b0011 → 0b1100

5. 32 >> 3

32 ÷ 2³ = 32 ÷ 8 = 4
ビット:0b00100000 → 0b00000100

6. 1 << 8

1 × 2⁸ = 256
ビット:0b00000001 → 0b100000000(9ビット目が立つ)
補足:256 = 2⁸ はバイト単位の計算でよく登場する数値。

9-1. シフト演算を使うと掛け算・割り算より高速になるのはなぜか説明してください。

解答欄
解答と解説

9-1. シフト演算が高速な理由

CPUには「シフト命令」が1命令として用意されており、1クロックで実行できる。 一方、乗算命令はビットを加算しながら積み上げる処理が必要なため、複数クロックかかる。

シフト演算: 0001 → 0010 (ビットを1つ左にずらすだけ = 1クロック)
乗算命令 : x × 2 (内部で繰り返し加算 = 数クロック)

ただし現代のコンパイラは x * 2 を自動的に x << 1 に最適化するため、 実務では読みやすいコードを優先し、手動でシフト演算に書き換える必要はほとんどない。

9-2. 以下のフラグ管理コードを読んで、コメントの(  )を埋めてください。

READ = 0b100 // 4
WRITE = 0b010 // 2
EXECUTE = 0b001 // 1
permission = READ | EXECUTE // → ( 1. )
// WRITE 権限があるか確認する
has_write = permission & WRITE // → ( 2. )なので、WRITE権限は( 3. )
解答欄
解答と解説

9-2. フラグ管理の読み取り

READ = 0b100
EXECUTE = 0b001
READ | EXECUTE の計算:
0b100
| 0b001
-------
0b101 → 10進数: 5
  1. permission の値 = 0b101(10進数: 5)
has_write の計算:
0b101 (permission)
& 0b010 (WRITE)
-------
0b000 → 10進数: 0
  1. has_write の値 = 0b000(= 0)
  2. 0 は「偽」を表すため、WRITE 権限は なし

このようにビット演算1つで複数の権限フラグを効率よく管理できる。 Linux のファイルパーミッション(chmod 755 など)も同じ仕組みで動いている。


問題10:ハンズオン(ビット演算)

Section titled “問題10:ハンズオン(ビット演算)”

Node.js で実際にビット演算・シフト演算の結果を確かめてください。

① AND・OR・XOR を確かめる

Terminal window
node -e "console.log((0b1100 & 0b1010).toString(2)); console.log((0b1100 | 0b1010).toString(2)); console.log((0b1100 ^ 0b1010).toString(2))"

出力が 1000, 1110, 110 になることを確認する。 (XOR の結果は先頭の 0 が省略されて 110 と表示される)

② シフト演算を確かめる

Terminal window
node -e "console.log(1 << 4); console.log(32 >> 2)"

出力が 16, 8 になることを確認する。

③ ビットマスクを確かめる

Terminal window
node -e "const v=0b10110111; const mask=0b00001111; console.log((v & mask).toString(2), v & mask)"

下4ビット(0b0111)が取り出され 111 7 と表示されることを確認する。 (toString(2) は先頭ゼロを省略するため 111 と表示される)

解答と解説

① AND・OR・XOR を確かめる

Terminal window
$ node -e "console.log((0b1100 & 0b1010).toString(2)); console.log((0b1100 | 0b1010).toString(2)); console.log((0b1100 ^ 0b1010).toString(2))"
1000
1110
110

XOR の結果 0110 は先頭の 0 が省略されて 110 と表示される。


② シフト演算を確かめる

Terminal window
$ node -e "console.log(1 << 4); console.log(32 >> 2)"
16
8

1 << 4 は 2⁴ = 16、32 >> 2 は 32 ÷ 4 = 8。


③ ビットマスクを確かめる

Terminal window
$ node -e "const v=0b10110111; const mask=0b00001111; console.log((v & mask).toString(2), v & mask)"
111 7

0b10110111(183)の下4ビットは 0111 = 7。マスクで上位ビットが消え、下4ビットだけが残る。 ネットワークのサブネット計算やカラーコードの RGB 分離にも同じ手法が使われる。