ソフトウェア入門
書誌
| text | 唯野 |
| author | 太田純 |
| publisher | ソフトバンク |
| year | 『C MAGAZINE 2001.8』p.39-56 |
| price | ? |
履歴
| 2001.7.23 | 読了 |
| 2001.7.23 | 公開 |
| 2002.11.28 | 修正 |
感想
同じく C マガの 「ハードウェア入門」 に続くソフトウェアの方の入門記事。こちらは言語の細かい歴史を除くとほとんどが既知の話題だったので、それなりにリラックスして読むことができた。とはいえ、知識の再確認という意味や、要領よくまとめられた内容は貴重だと思ったので、こちらもまとめておく。いずれにせよセットで理解しておくというのが本道だろう。
抄録
データ表現と演算
bit は binary digit の略のこと。n 進数の n のことを基数といい、n 進数の下から m 桁目はそれぞれ n の m-1 乗の値で、これを重みという。10 進数を 2 進数に基数変換するには、10 進数を 2 で割ることを繰り返して余りを逆順に並べる。逆は 2 進数の下から n 桁目に重み 2 の n-1 乗をかけて合計すればよい。
2 進数には符号がないので負の数を表現するのに補数(多くの計算機では 2 の補数 : 2's complement)を使い、ある値の補数が元の値の負数だと解釈する。n 桁の 2 進数に対応する補数は、その全ビットを反転させて 1 を加えたものになる。2 の補数は 0 の補数が(桁上がりを無視すれば) 0 になり、0 の正負を反転しても 0 になる、最上位ビットが 1 なら負数になる、減算を補数の加算として扱えるなどコンピュータの計算にとって都合がよい。
論理演算で入出力の並べた表のことを真理値表という。論理否定(NOT)は入力ビットの反転、論理積(AND)は入力が共に 1 の場合だけ出力も 1 (その他は 0)、論理和(OR)は入力が共に 0 の場合だけ 0 (その他は 1)、排他的論理和(XOR)は入力のいずれかが 1 なら 1 (その他は 0)になるものを指す。
2 進化 10 進法(BCD : Binary Coded Decimal)とは固定小数数を表現するためのデータ形式をいい、4 ビットに 10 進 1 桁の数値を 2 進数として格納する。浮動小数点数に比較して、小数点以下の 10 進数が正確に表現でき、計算誤差の発生しない特徴がある。(COBOL ではこれが使われている。)一方、浮動小数点数(一般に IEEE のものが使われる)は仮数部(m)、指数部(e)、符号から成り、数値は m * 2 の e 乗として表現される。
プログラミング言語
プログラミング言語を言語処理系から分類すると次のようになる。
| 分類 | 内容 |
| アセンブラ(assembler) | アセンブリ言語のソースプログラムから、直接的に実行可能プログラム(executable)を出力する。アセンブリ言語の命令は機械語命令に覚えやすい名前(ニーモニック:mnemonic)を付けたもので機械語命令に 1 対 1 で対応する。また、データとなるアドレスに記号名を付けることができる。(アドレス変換を自動で行える。) |
| コンパイラ(compiler) | ソースが機械語命令とは 1 対 1 でなく、ソースがどう翻訳されるかは文脈に依存する。一般にコンパイラは字句解析部(lexical analyzer)、構文解析部(paser)、コード生成部(code generator)、最適化部(optimizer)で構成される。オブジェクトプログラムから実行可能プログラムを作るのにリンカ(linker)を使う。リンカはオブジェクトプログラムと実行開始ルーチン、ライブラリを結合して実行可能プログラムを出力する。 |
| インタプリタ(interpriter) | ソースプログラムを読んで逐次解釈・実行するプログラム。インタプリタというソフトウェアに対する入力がソースプログラムというかたちになり、そのためアセンブラやコンパイラよりも速度が低下する。そのため、最近では中間コード(仮想的な機械語命令)にいったんコンパイルしてから実行されることが多い。 |
| トランスレータ(translator) | あるプログラムを別の言語に変換するプログラム。 |
| ジェネレータ(generator) | 書式や仕様の定義から、それの実現するソースプログラムを生成するもの。 |
| エミュレータ(emulator) | ある計算機で別の計算機のプログラムを実行するプログラム。これとは別にある計算機で別の世界の模倣するものはシミュレータ(simulator)と呼ぶ。 |
次にプログラミング言語を分類すると次のようになる。
| 分類 | 内容 |
| 手続き型言語 | 必要な命令文を実行順に並べて組み立てる言語。この実行順序は if、for、goto などによる制御構造で行われ、関数や手続きの呼び出しを伴う。FORTRAN、COBOL、C など。 |
| 関数型言語 | 初期データをある関数に渡し、その結果をまた別の関数に渡すという関数の入れ子によってプログラムを構成する。制御構造は引数評価の選択を行う関数や再帰呼び出しによって実現する。Lisp、Scheme、ML、Haskel など。 |
| 論理型言語 | 述語論理によって知識データベースを組み立て、それへの問い合わせによって問題解決の行う言語を指す。Prolog など。 |
| オブジェクト指向言語 | 処理対象をオブジェクト(データと操作のまとめたもの)と捉えることで、抽象度の高いプログラムを実現するもの。Simula、Smalltalk、Eiffel、C++、Objective-C、Java など。 |
代表的なプログラミング言語として以下がある。共通点として、どの時代でも機能を詰め込みすぎて肥大化した言語は広く普及していないことが挙げられる。
FORTRAN (1957)
世界初の高水準言語。FORmula TRANslator (数式変換器) の略で、科学技術計算の場でよく使われた。最初の FORTRAN は IBM 704 計算機のために書かれたが、FORTRAN IV によって互換コンパイラが広がったため、ANSI によって FORTRAN 66 となった。但し、言語としての機能は現在から見ると、それほど高くなく、その後の改良で FORTRAN 77、FORTRAN 90 が標準化されている。FORTRAN は過去の膨大な資産により、現在でも現役として利用されている。
COBOL (1959)
米国の計算機メーカーによる CODASYL (the COnference on DAta SYstems Language) によって制定されたのが COBOL (COmmon Buiness Oriented Language) で、名前の通り事務処理に向いていた。特徴としてデータがレコードを単位として扱われ、固定小数点数により桁数によっても誤差の許されない金額計算に適していた点が挙げられる。また、プログラムが英文に近い表現であり、教育コストを下げる効果も持っていた。
Lisp (1962)
MIT のジョン・マッカーシー教授が人工知能研究のために考案したのが Lisp (LISt Processor)で、名前の通り、リスト構造を処理するための言語だった。Lisp では全てがリスト構造となり実行中に新たなプログラムを組み立てて呼び出せる(自身が成長できる)。また、関数型言語のため全ての処理が関数呼び出しとして実現される。(但し、ソースは ( ) のネストなどにより読みにくい。)Lisp には様々な方言があり、現在では MacLisp の機能を統合した CommonLisp が標準的に使われている。Emacs は CommonLisp インタプリタを備え、様々な編集機能を Lisp で実現している。
Algol (1958)
上記の 3 つがアメリカで誕生したのに対し、ヨーロッパで生まれたのが Algol (ALGOrithmic Language) で、アルゴリズムの研究開発を目的としていた。Algol では手続きを入れ子にでき、また再帰を実現した最初の言語だった。初期の Algol58 はすぐ Algol60 となり、その後 Algol68 として構造化プログラミングのための機能が追加された。その意味で、その後の手続き型言語全般に Algol は影響を与えている。
PL/I (1964)
IBM が機種依存のプログラミング言語を統合しようとして誕生させたのが PL/I (Programming Language/One) で、FORTRAN の構文、COBOL のデータ構造、Algol60 の手続きとブロックを持ち、汎用性を持っていたが、逆にコンパイラが複雑で巨大なため使用できる環境も制限され、広く普及するには至らなかった。
BASIC (1964)
ダートマス大学のケメニーとカーツが時分割システムのために作ったのが BASIC (Beginner's All-purpose Symbolic Instruction Code : これは後付けの名前) で、対話型処理に向く簡潔な構文とインタプリタという点に特徴がある。BASIC は言語としてよりもプログラミング環境として認知され、初期の PC では OS 兼プログラミング環境として広く利用された。しかし、方言が多く生まれ互換性を失っている。
PASCAL (1971)
チューリッヒ連邦工科大学のニクラウス・ヴィルト教授がアルゴリズム学習用のプログラミング言語として作ったのが PASCAL で、その名前は世界最古の計算機を発明したといわれる数学者ブレーズ・パスカルに由来する。goto への制約など構造化の行いやすい特徴によって、教育用に広く普及した。しかし、PASCAL 自身は複雑な部分を極力排除したものだったため実用には非力という側面があり、言語に対する拡張が行われた。カリフォルニア大学サンディエゴ校(UCSD)の UCSD Pascal は中間コードインタプリタ形式の Pascal で、また Borland は高速な Pascal コンパイラを持つ Turbo Pascal を作り、PC 上の開発言語として普及した。Turbo Pascal をオブジェクト指向に拡張したのが Delphi である。
Simula (1967) / Smalltalk (1972)
オスロ大学のダールらがシミュレーション記述のために作ったのが Simula で、シミュレーションの対象をオブジェクトとしたクラス、メソッド、インスタンスなどオブジェクト指向プログラミングの基本要素を備えていた。そして、Xerox PARC (パロアルト研究所)のアラン・ケイが世界初の GUI WS である Alto の統合開発言語として Simula の発展形である Smalltalk を作った。Smalltalk では全ての処理はメッセージの受け渡しとして実現され、その後のオブジェクト指向言語に大きな影響を与えた。
Prolog (1972)
マルセイユ大学のコルムラウアらにより述語論理に基づく論理型プログラミング言語として誕生したのが Prolog (PROgrammation en LOGique) で、自然言語処理や人工知能研究で利用されている。特徴はホーン節と呼ばれる形式で知識を記述し、その集積がプログラムとなる点で、内部では知識に対するバックトラックによるパターンマッチングを行っている。
C (1972)
C は系譜的にいうと Algol60 -> CPL -> BCPL -> B -> C という流れを汲んでいる。元々は UNIX のシステム記述言語だがポインタ型や低レベル操作の演算子による記述能力の高さから爆発的に普及し、あらゆる環境で利用されている。しかし、初期の処理系(K&R)ではライブラリ関数も仕様には含まれていなかった。
Ada (1980)
米国国防総省の開発した汎用言語が Ada で軍用アプリケーション開発に使われている。名前は世界初のプログラマといわれるエイダ・オーギュスタ・ラブレイス(詩人バイロンの娘)に由来する。プログラムは仕様と本体から成るパッケージと呼ばれるモジュールの集合で、パッケージの実体がタスクとなり並列動作ができる。また、ランデブーと呼ばれるプロセスをオブジェクトと見なしてメッセージ交換する仕組みを持っている。構文的には PASCAL を受け継いでおり、例外処理を独自に持っている。厳密な並列処理などに向いているが、言語仕様や処理系が複雑なため広くは普及していない。
C 以降
C は幅広く普及したが、抽象化の機能が欠けていたため、それを補うものがその後登場した。Simula の概念を導入したのが C++ (1983) で、一方 Smalltalk の概念を受け継いだのが Objective-C (1983) となる。(NeXTStep は Objective-C で記述されていた。)また、C++ をシンプルにしたともいえるのが Java で(ポインタがなく参照を使うなど)、Java 仮想マシンの導入によりプラットフォーム独立のメリットがある。主にネットワーク上でのアプリケーション開発で用いられている。
アルゴリズムとデータ構造
アルゴリズム(algorithm)とは「ある問題を解くための一般化された計算手順」のことで、プログラムとは問題に対するアルゴリズムとデータ構造の組み合わせを表現したものということができる。(ちなみにアルゴリズムとはアラビアの数学者、アル=フワリズミに由来する。)一般にアルゴリズムとデータ構造はトレードオフの関係にある。アルゴリズムとして表駆動(table driven)と木構造、番兵(centinel)などを使うと、プログラムの持つ意味的な変化のもたらされることが分かる。また、アルゴリズムの違いは計算量に大きな違いをもたらす。データ数に対する処理時間の関係のことを計算量(Order)といい、関数 O で表す。アルゴリズムの選択では自分が解こうとする問題の特質をよく理解することが重要になる。
ソフトウェア開発技法
大規模プロジェクトなどでは開発にもソフトウェア工学に則ったアプローチが使われる。まず、代表的なシステム開発モデルとして以下がある。
分類 内容
ウォーターフォールモデル 開発段階を工程に分け上流から下流へ滝の流れるように進めるもの。各工程は前の工程が終了してから進み、原則として後戻りはしない。管理しやすいという利点を持つが、初期段階での仕様の確認が難しく、仕様変更が難しいという欠点を持つ。
プロトタイプモデル 開発の初期段階でプロトタイプを開発してユーザが評価して要求仕様を確認するタイプのもの。
スパイラルモデル ウォーターフォールとプロトタイプの双方の特徴を取り入れたもので、中心的なサブシステムから細かいウォーターフォールを繰り返して開発を行う。オブジェクト指向システムに向いている。
ラウンドトリップモデル 分析、設計、実装の間を往復しながら、トライアンドエラーで開発を行うタイプ。自由度が高いが、工程管理のしにくいという特徴を持つ。
ウォーターフォールモデルでは一般に内部設計までが上流工程、それ以降が下流工程となり、以下の流れを踏む。
- 外部設計 (ユーザ側からの機能設計)
- 内部設計 (システム側からの機能設計)
- プログラム設計 (プログラム構造の設計)
- コーディング (設計に基づくプログラム作成)
- テスト (プログラムの動作確認)
- 保守 (運用開始後の保守作業)
# この辺は IIOSS の記事 も参照されたし
構造化プログラミングとはトップダウン開発技法のひとつで根底として分割統治(division and conquer)という概念がある。これは大きな問題を小さな問題に分割して解決しようとするもので、そのために抽象化(システムの本質の抜き出し)、段階的抽象化(実現すべき機能の細分化、具体化)、構造的プログラム(実装)という 3 つの手法に基づいた設計・開発を行う。実装は連接、選択、反復の組み合わせとして記述される。構造化プログラミングの思想に影響を与えたものとして、ダイクストラの「Go To Statement Considered Harmful」(1968)による goto 有害論などがある。
Psacal 以降の手続き型言語はいずれも構造化プログラミングの基本制御構造(連接・選択・反復)を備えているが、構造化プログラミングになじみにくいもののひとつとして例外処理がある。このため C++/Java の throw/catch、Ada の raise/exception といった言語レベルで例外処理をサポートするものがある。
