コンピュータって何?

上級の解説は準備中のため、上級の内容を表示しています。

概要 — まず全体をつかむ

中級では、コンピュータを5大装置フォンノイマン型という骨格でとらえ直しました。上級では、その骨格がなぜ「指示を差し替えるだけで何にでも化ける」のか——その原理まで降ります。そして万能に見えるこの機械にも、原理的な限界と物理的な限界があることまで見ます。

前提として、この機械が最終的に扱うのは 0 と 1 だけです。その土台は 2進数とデータ を参照。

詳細 — 1段階ずつ追う

指示を差し替えるだけ — ストアドプログラム方式

ノイマン型の核心は「プログラムをどこに置くか」にあります。

  1. 昔の機械は、処理内容を物理的な配線(※1)で決めていた。別の計算をさせるには配線を組み替える必要があった
  2. ノイマン型は、プログラムをデータと同じ主記憶に格納する。命令も 0 と 1 の並びとして置く
  3. だから機械にとって命令列は、読み書きできるただのデータでもある
  4. 別の仕事をさせたいときは、配線ではなくメモリの中身(指示書)を差し替えるだけでよい

登場人物メモ(※の説明):

  • ※1 配線で決める方式 — 処理を回路の結線そのもので固定する古い作り。差し替えが利かず、汎用性がない
  • ※2 ストアドプログラム方式 — 命令とデータを同一メモリに置く方式。プログラム内蔵方式・ノイマン型とも呼ぶ

この「命令もデータとして扱える」性質が、コンパイラ(プログラムを別のプログラムに変換する道具)や、実行中に自分を書き換える処理まで可能にします。同じ CPU が電卓にもブラウザにもなるのはこのためです。CPU 側の詳しい動きは CPU を参照。

⚠️ イレギュラー — 命令とデータが同じメモリ・同じ通り道(バス)を共有するため、そこが渋滞点になるフォンノイマンボトルネックが生じます。また「命令もデータ」という性質は諸刃で、データのつもりの領域を命令として実行させる攻撃(コードインジェクション)の温床にもなり、命令用とデータ用のメモリを分けるハーバードアーキテクチャが選ばれる場面もあります。

1つずつ回す — 命令実行サイクル

「指示どおり順に計算する」の"順に"の正体が、この繰り返しです。

  1. フェッチ — プログラムカウンタ(※1)が指すアドレスから命令を1つ取り出し、カウンタを次へ進める
  2. デコード — 取り出した命令が「何をせよ」なのかを制御装置が解読する
  3. 実行 — 演算装置などが実際に計算・比較・データ移動を行う
  4. 書き戻し — 結果をレジスタ(※2)や主記憶に書き込む
  5. 1へ戻る。分岐命令ならカウンタの値を書き換え、別の場所へ飛ぶ

登場人物メモ(※の説明):

  • ※1 プログラムカウンタ — 次に実行する命令のアドレスを保持する小さな記憶。逐次実行の「しおり」
  • ※2 レジスタ — CPU 内部にある極小・極速の作業メモリ。計算の途中値を置く
アニメーション『命令サイクル』を開く
命令サイクルぐるぐる繰り返す① フェッチ(取得)メモリから命令を取ってくる② デコード(解読)命令の意味を読み解く③ 実行演算・分岐・メモリ操作④ ライトバック結果をレジスタ/メモリへ書き戻すCPUはこの4段を高速に繰り返して命令を処理し続ける

この単純な4手を毎秒何十億回も回すことで、複雑に見えるすべての処理が組み上がります。分岐(if)もループも、突き詰めればカウンタの値を書き換えているだけです。

⚠️ イレギュラー — 現実の CPU は1命令を待ってから次、では遅すぎるので、複数命令を流れ作業で重ねるパイプラインで高速化します。ところが分岐の行き先が読めないと、先読みが外れて途中まで進めた作業を捨てる(分岐予測ミス)ことになります。さらに外部からの割り込みが入ると、サイクルの途中でも現在の状態を退避し、別の処理へ切り替えます。

下を隠して積み上げる — 抽象化の階層

なぜ人間がこの機械を扱えるのか。答えは、層を積んで下の複雑さを隠しているからです。下から順に積み上がります。

  1. トランジスタ — 電気のオン/オフを切り替える極小スイッチ(※1)
  2. 論理ゲート — トランジスタを数個組み、AND・OR・NOT の判断を作る
  3. 算術回路 — ゲートを束ね、足し算や比較ができる回路にする
  4. 命令 — 回路の操作に「加算せよ」「移動せよ」と名前を与える(機械語)
  5. プログラム — 命令を並べ、人間が読める言語で意味のある仕事を書く

登場人物メモ(※の説明):

  • ※1 スイッチとしてのトランジスタ — オン/オフで 0 と 1 を表す。ビットの物理的な正体
  • ※2 抽象化 — 下の層の詳細を隠し、上の層には「守るべき約束(インタフェース)」だけを見せる考え方
アニメーション『ビット=スイッチのオン/オフ』を開く
ビット = スイッチのオン / オフ1つのスイッチ = 1ビット(bit)ON = 1OFF = 0スイッチ8個 = 1バイト(byte)= 8ビット012816403201618040201各スイッチの重み(128〜1)。ONの重みを足すと数になる010010008ビットの並び(1バイト)数として読むと … 64 + 8 =72文字コードで読むと … 文字Hすべては0と1の並び。「読み方のルール」で意味が決まる

各層は、下がどう作られているかを知らなくてよいように設計されます。プログラムを書く人はトランジスタの電圧を意識しません。約束さえ守られれば、下の実装(例: 別の半導体、別の CPU)が入れ替わっても上はそのまま動きます。この積み重ねこそ、巨大な複雑さを人間が扱える理由です。0 と 1 がどう情報になるかは 2進数とデータ が担当します。

⚠️ イレギュラー — 抽象化は「隠す」だけで「切り離す」わけではありません。土台の層が壊れれば上も動きません。隠された下の層が漏れ出て上の挙動に影響することを抽象化の漏れ(leaky abstraction)と呼びます。たとえば、メモリを無限の平地とみなして書いたプログラムが、実際のキャッシュ階層(速い記憶と遅い記憶の段差)の都合で急に遅くなる、といった形で下層が顔を出します。

何でも計算できる、でも全部は解けない — 万能性と限界

十分な記憶と時間があれば、この機械は原理的にあらゆる計算をこなせます。これをチューリング完全(※1)と呼びます。だが「何でも計算できる」は「何でも解ける」ではありません。

  • 万能性 — 命令の並べ方しだいで、電卓にも AI にもなる。ハードは同じでよい
  • 決定不能な問題 — 任意のプログラムが停止するか無限ループに陥るかを、一般に判定する手続きは存在しない(停止性問題※2)。これは性能ではなく原理の限界で、どれだけ速くしても解けない
  • 計算量の限界 — 解けはするが現実的な時間で終わらない問題もある(組み合わせ爆発)
  • 物理の限界 — 微細化(トランジスタを小さく詰める)はいずれ原子サイズの壁に近づく。周波数を上げれば発熱と消費電力が急増する(電力の壁・発熱の壁)

登場人物メモ(※の説明):

  • ※1 チューリング完全 — 十分な記憶があれば、計算可能なものは何でも計算できるという能力の広さ
  • ※2 停止性問題 — 「このプログラムは止まるか」を万能に判定する方法は作れない、という決定不能の代表例

だからこそ設計は、1つのコアをひたすら速くする路線から、複数コアで手分けする並列化へ舵を切りました。ただし並列化にも上限があります。処理の中に順番を守らねばならない部分が残る限り、コアを増やしても全体はそこまで速くならない(アムダールの法則)——直列の鎖は人手を増やしても縮まないのと同じです。プログラムがこの機械の上で実際にどう走るかは アプリとOS を参照。

⚠️ イレギュラー — 「速い機械なら停止性問題も解ける」は誤解で、これは原理的に解けません。また「コアを倍にすれば倍速」も誤りで、直列部分がボトルネックになり頭打ちします(アムダールの法則)。物理的にも、微細化・発熱・並列化の壁が同時に効いてくるため、性能向上は「1つを速く」から「賢く手分け・省電力」へと質を変えています。

関連する知識

理解度チェック

そのまま解けます(成績は保存されません)。無料アカウントを作ると、学習の記録と進捗の山登りが始まります。

1. 命令実行サイクルをフェッチ→デコード→実行→書き戻しの順で回すとき、次に取り出す命令の在り処を指しているのはどれ?

2. トランジスタ→論理ゲート→算術回路→命令→プログラムという抽象化の積み重ねについて、正しい説明はどれ?

3. 「チューリング完全」と「停止性問題」について、正しい組み合わせはどれ?

4. 近年、CPUのクロック周波数の伸びが頭打ちになり、コア数を増やす方向(並列化)に舵を切った主因はどれ?

5. パイプラインで先読みした分岐(if)の行き先が外れたとき、何が起きるか?

6. コアを倍に増やしても処理が単純に倍速にならない理由を説明する法則はどれ?

7. 命令用メモリとデータ用メモリを分離し、フォンノイマン型と対比される構成を何と呼ぶ?

8. ストアドプログラム方式(プログラム内蔵方式)の本質を最もよく表しているのはどれ?