ホーム » 2019 (ページ 12)
年別アーカイブ: 2019
2019年度情報構造論ガイダンス
情報構造論のガイダンス
プログラムを評価する3つのポイント
この授業で恒例の、プログラムを作る場合に何に気をつけてプログラムを作成するかを聞いてみた。今年は、以下に示す3要素をうまく答えてくれたかな。
- プログラムの速度
- プログラムのわかり易さ
- メモリの使用量
プログラムを作る場合、この3要素がトレードオフの関係にある。プログラムの速度を優先すると、プログラムが分かり難くなったり、メモリを大量浪費するものだったりする。
メモリの使用量の影響
メモリを大量に使用すると、どういった影響がでるのか? OSの機能を知らないと、メモリ(主記憶)を使い果たしたら、プログラムが動かないと思うかもしれないけど、最近のOSは仮想メモリ機能があるため、主記憶がメモリが足りなければ待機状態のプロセスのメモリを補助記憶に保存することで、プログラムを動かすことはできる。(仮想記憶)
しかし、プロセスが切り替わる度に、補助記憶への読み書きが発生するため、処理性能は低下する。(スワッピング)
ソフトウェアとアルゴリズムとプログラム
用語として、ソフトウェア、アルゴリズム、プログラムという表現があるが、この違いは何か?
- アルゴリズム – 計算手順の考え方。
- プログラム – アルゴリズムを特定のプログラム言語によって記述したもの。
- ソフトウェア – プログラムと、その処理に必要なデータ。(日本語を変換するプログラムは、日本語の辞書データが無いと動かない)
トレードオフ関係をプログラムで確認
例えば、配列の中から、目的データを探すプログラムの場合、最も簡単なプログラムは以下の方法であろう。
// ((case-1)) // 単純サーチ O(N) #define SIZE 1024 int a[ SIZE ] ; // 配列 int size ; // 実際のデータ数(Nとする) int key ; // 探すデータ for( int i = 0 ; i < size ; i++ ) if ( a[i] == key ) break ;
しかし、もっと早く探したいのであれば、2分探索法を用いるだろう。でも、このプログラムは、case-1 のプログラムよりは分かり難い。(速度⇔わかり易さ)
// ((case-2)) // 2分探索法 int L=0 , R=size ; // プログラムは複雑になった while( L != R ) { int M = (L + R) / 2 ; if ( a[M] == key ) break ; else if ( a[M] < key ) L = M + 1 ; else R = M ; }
でももっと速いプログラムとしたければ、大量のメモリを使えば一発でデータを探せる。(速度⇔メモリ使用量)
// ((case-3)) // 添字がデータ O(1) // 探すデータが電話番号 272925 のような 6 桁ならば int a[ 1000000 ] ; a[ 272925 ] = 272925 ; // 処理速度はクソ速いけど、メモリは大量消費
良いプログラムを作るとは
プログラムを作る時には、メモリが大量に使えるのなら、速いものを使えばいい。だけど実際には、そのシステムには限られた予算があるだろう。
実際には、限られる予算から、メモリやCPUが決まり、その会社の人員やら経験やらで、プログラム開発に使える時間がきまる。プログラムをデザインするとは、限られた条件の中で、適切な速度のコンピュータ、適切な量のメモリでコンピュータを用意し、限られた納期の中でシステムを完成させることである。
動作時間の予測
ここで、プログラムの実行時間を細かく分析してみる。例えば、前節のcase-1の単純サーチをフローチャートで表せば、以下のように表せるだろう。フローチャートの各部の実行回数は、途中で見つかる場合があるので、最小の場合・最大の場合を考え平均をとってみる。また、その1つ1つの処理は、コンピュータで機械語で動くわけだから、その実行回数の繰り返した分の処理時間を要する。この時間を とする。
この検索処理全体の時間 を考えると、平均時間とすれば、以下のように表せるだろう。
ここで例題
この単純サーチのプログラムを動かしてみたら、データ件数N=1000で、5μ秒かかったとする。では、N=10000であれば、何秒かかるだろうか?
感のいい学生であれば、直感的に 50μ秒 と答えるだろうが、では、Tβ,Tα は何秒だったのだろうか? 上記のT(N)=Tα+N ✕ Tβ に当てはめると、N=1000,T(N)=5μ秒の条件では、連立方程式は解けない。
ここで一番のポイントは、大量のデータ処理を行うのが普通だから、N が小さな値の場合はあまり考えない。N が巨大な値であれば、Tαは、1000Tβに比べれば微々たる値という点である。よって
で考えれば良い。これであれば、T(1000)=5μ秒=Tβ×1000 よって、Tβ=5n秒となる。この結果、T(10000)=Tβ×10000=50μ秒 となる。
学生による研究発表会に参加
平成30年度 北陸地区学生による研究発表会が、富山高専本郷キャンパスにて3/2(土)に開催され、福井高専の電子情報からは、5EIより6名・専攻科1年より1名の計7名の学生が参加しました。
5年の学生さんは、卒業研究での質疑応答とは違う視点での質問などもあり、研究を進めるにあたり幅広い見地の必要性を感じたのではないでしょうか?
専攻科研究フォーラムに参加
専攻科では学内の発表も終えましたが、他の高専の学生さんも交えた専攻科研究フォーラムが開催されました。
電子情報系からは山田くんがポスターセッションでの発表となりました。他にも福井高専からは他学科より5名の参加となりました。
gcj (GNU Compiler for Java) の使い方
いつもは Java を使わないけど、久々に java のプログラムの動作実験と思い、サーバ機に gcj (GNU Compiler for Java)を入れて使おうとしたら、コンパイラ javac とバイトコードインタプリタ java のつもりでコマンドを探すけど、見つからない。
gcj を見つけて “gcj HelloWorld.java” ってやってみたけど動かない。あらためて確認したら、バイトコード生成もできるし、直接機械語も生成できるけど、色々とオプション指定がいるみたい。なるほど。
// HelloWorld.java public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } }
# 機械語を直接生成する場合 $ gcj -o HelloWorld --main=HelloWorld HelloWorld.java $ ls HelloWorld HelloWorld.java $ ./HelloWorld Hello World! # バイトコードを生成して動かす場合 $ gcj -C HelloWorld.java $ ls HelloWorld.class HelloWorld.java $ gij HelloWorld Hello World!
情報構造論2018-講義録
情報ネットワーク基礎後半レポート課題
情報ネットワーク基礎の後半のレポート課題は、以下の通り
メールがどのように届いたか
自分宛にメールを出し、そのメールヘッダなどの内容を確認し、そのメールがどの様に届いたか確認し、状況をレポートにまとめ提出せよ。
レポートでは、以下の点をまとめること。
- どのように出したメールか
- メールヘッダなどをどのように確認したか
- メールヘッダから何が分かるか。
“Received:” タグなどに何が記載されIPアドレスとそのホスト名などの値を確認せよ。その他の主要なメールヘッダについても、どういった内容が記載されているのか確認し、メールの仕組みについて考察すること。
なお、個人のメールアドレスなどが、知られたくない場合は該当部分を部分的に消して資料を作成すれば良い。
書類のマナーを守ること / 追記(2019/02/14)
テスト返却日を前にレポートがメールで送られてくる。
ただ、課題レポートのマナーとか、メールのマナーがダメダメ。
課題レポートのマナー
今回は、メールの状態を調べてた内容のレポート。でも、Wordで記載して送ってくるとしても、誰が記載したどういったレポートなのか分からないものばかり。遅れてレポート課題を提出してくる可能性もあるのだから、
- 課題タイトル・学科・学年・氏名
は先頭に明記すべきだろう。「ファイル名で判るでしょう?」という反論はあるかもしれないけど、印刷して保存されることも考慮するのがビジネス書類のマナー。
ビジネス書類であれば、
- 基本はA4(もしくは相手が指定した書類サイズ)
- 印刷&ファイリングを想定して左余白をとること
今回は、メールの内容を調べるという課題とはいえ、実験レポートの記載マナーに沿って、
- 課題の概要(どういった内容を調べたのか)
- 実験の方法(今回なら、どこのメールアドレスからどこに送ったのか)
- 実験は再現性があることが絶対条件。
- 記載した図などには、図番号、表番号、プログラムリスト番号付け、本文で引用すること
といった内容も記載すべき。
ファイル名も、別課題などと区別できるように、”3EI-45-ほげ太郎-メール調査.docx” といったものが望ましいかな。
メールの詳細調査 3EI 45 ほげ太郎 1. 目的 メールの仕組みを理解するために、個人のメールアドレスから学校のメール アドレスにメールを送った時の、メールヘッダを解析し、メールの仕組みを 理解する。 2. 調査方法 自分の個人メールアドレスには、au のメールアドレス xxxxxx@ezweb.ne.jp を使い、学校のメールアドレス s99945ht@fukui.kosen-ac.jp にタイトル 「じっけん」、本文「写真の添付も付けてみた」、添付ファイルに、1024x640 pixcel の写真を付けて送信を行った。 3. 送信および受信の結果 送信の際の添付画像を図1に示す。 図1の写真を掲載 学校のメールアドレスに届いたものを、WebブラウザでOffice365を開き、 Outlook の機能を使って受信を確認した。(図2参照) 図2の写真を掲載 この内容を、Outlookの ...... の詳細を使って得られたヘッダは、 図3のような情報であった。 図3の内容を掲載 4. メールヘッダの詳細の内容 :
メールのマナー
ビジネスメールであれば、もっと細かいマナーがあるけど、最低限でも
- 誰が出したか判るようにすること。学校のメールアドレスだとしても、本人が誰かすぐに判るようにすべき。
- メールタイトルを明記すべき。ここで誰か判るように名前を書くのもアリだけど、本来は要件を書くべき。今回なら、「情報ネットワーク基礎の後半課題」といった内容だろう。
これを踏まえると、必要最低限でも、メールを出すなら次のようになるだろう。
From: s99945ht@fukui.kosen-ac.jp To: t-hoge@fukui-nct.ac.jp Subject: 情報ネットワーク基礎のメール調査の課題(3EI45 ほげ太郎) 情報ネットワーク基礎のメール調査の課題を、 添付ファイルにて提出します。 -- 3EI 45 ほげ太郎 ← こういう部分はシグネチャ(署名)と呼ばれる
ただし、会社でのビジネスマナーであれば、もっと細かい注意が必要。
本文の先頭に送付先の名前などの「◯◯様」を書くとか、軽い挨拶の1行で始めて、最後は御礼の一言で締めるとか…。
オブジェクト指向と演習
データ構造を扱うプログラムの書き方を説明してきたので、それらを便利に書くためのオブジェクト指向の入り口を紹介する。
データ指向のプログラム記述
名前と年齢のデータを扱うプログラムを書く時、私なら以下のようなプログラムを作成する。
このプログラムの書き方では、saitohというデータにset_NameAge() , print_NameAge() を呼び出していて、データに対して処理を加えるという雰囲気がでている。このようにプログラムを書くと、saitoh というデータに対して命令するイメージとなり、擬人化してset,printしろ…って命令しているように見える。
// 名前と年齢の構造体 struct NameAge { char name[ 20 ] ; int age ; } ; // NameAgeを初期化する関数 void set_NameAge( struct NameAge* p , char s[] , int a ) { strcpy( p->name , s ) ; p->age = a ; } // NameAgeを表示する関数 void print_NameAge( struct NameAge* p ) { printf( "%s %d¥n" , p->name , p->age ) ; } void main() { struct NameAge saitoh ; set_NameAge( &saitoh, "t-saitoh" , 53 ) ; print_NameAge( &saitoh ) ; // NameAge の中身を知らなくても、 // set_NameAge(),print_NameAge() の中身を見なくても、 // saitoh を set して print する....という雰囲気は伝わるよね!! }
このプログラムでは、例えば、データに誕生日も覚えたいという改良を加えるとしても、main の前のデータ構造と関数の部分は色々と書き換えることになるだろうけど、main の内部はあまり変わらないだろう。こういう状態なので、プログラムを作成するときには、データ構造とそれを扱う関数を記述する人と、データ構造を使う人(main内部を書く人)と、分業ができるようになる。
隠蔽化
このような記述では、データ構造の中身を知らなくても、main で、setしてprintして…という処理の雰囲気は分かる。さらに、set_NameAge()とか、print_NameAge() の処理の中身を知らなくても、設定するとか表示するとか…は予想できる。
これは、NameAge というデータをブラックボックス化して捉えていると見れる。データ構造の中身を知らなくてもプログラムを理解できることは、データ構造の隠蔽化という。また、関数の中身を知らなくても理解できることは、手続きの隠蔽化という。
オブジェクト指向プログラミング
前述のように、プログラムを書く時には、データ構造とそのデータを扱う関数を一緒に開発するのが一般的である。オブジェクト指向プログラミングでは、データ構造とその関数(メソッドと呼ぶ)をまとめてクラスと呼ぶ。
class NameAge { private: // データ構造の宣言 char name[ 20 ] ; int age ; public: // メソッドの定義 void set( char s[] , int a ) { // 初期化関数 strcpy( name , s ) ; age = a ; } void print() { // 表示関数 printf( "%s %d¥n" , name , age ) ; } } ; void main() { NameAge saitoh ; saitoh.set( "t-saitoh" , 53 ) ; saitoh.print() ; }
このプログラムでは、saitoh というデータ(具体的なデータはオブジェクトと呼ぶ)に対して、set() , print() を呼び出している。
オブジェクト指向では、データに対して private を指定すると、クラス以外でその要素を扱うことができなくなる。これにより、クラスを設計する人と、クラスを使う人を明確に分けることができ、クラスを使う人が、クラス内部の変数を勝手に触ることを禁止できる。
プログラムを記述する時には、データ件数を数える時に、カウンタの初期化を忘れて動かないといった、初期化忘れも問題となる。オブジェクト指向のプログラム言語では、こういうミスを減らすために、データ初期化専用の関数(コンストラクタ)を定義することで、初期化忘れを防ぐことができる。
// コンストラクタを使う例 class NameAge { // 略 public: NameAge( char s[] , int a ) { // データ初期化専用の関数 strcpy( name , s ) ; // コンストラクタと呼ぶ age = a ; } // 略 } ; void main() { NameAge saitoh( "t-saitoh" , 53 ) ; // オブジェクトの宣言と初期化をまとめて記述できる。 saitoh.print() ; }
演習(ハッシュ法)
ハッシュ法のプログラム(オープンアドレス法もしくはチェイン法)を用いて、
(1)名前と電話番号,(2)名前と住所,(3)名前と誕生日について、名前をキーとして検索するプログラムを作成せよ。
原則として「出席番号 % 3 + 1」の番号のテーマに取り組むこと。
レポートを作成する際には、ハッシュ関数を変更してどういった変化があるか確認せよ。
ハッシュサイズは、10〜20件程度で良い。
緊急連絡システムでrblsmtpd
メモ:緊急連絡システムで、迷惑メールが届いている。変なリレーはされていないけど、エラーメールが配送できずに溜まってる。
設定を改めて確認して、迷惑メール対策が弱いのでブラックリストなメールサーバからの受信をしないように、rblsmtpd を導入。rblsmtpdの設定は、以前の運用経験からすぐに設定できるかと思ったけど qmail が systemd 用に設定ファイルが変わっているので、修正場所を探すのに手間取った。