2015年4月19日(第419回)
- まるよし Train Pops ~ 国語と遊ぼう! 第99便 「最後の授業」 後編
- 海外に旅立ってしまう先生が最後の授業で黒板に何とかいたか?というテーマで大喜利をしました。
- 新学期の授業について
- 新入生歓迎会について
担当:田嶋(3C・MIX)、山田(2B・MC)、稲葉(2EI)、西(教員)
授業アンケートの結果
授業アンケートが、年度末に演習室が使えなかったことから、 時期遅れではあるけれど、結果がでてきた。
プログラミング応用は、昨年度の81.7からは、若干落ちて76.3ポイント。 Q4の板書について、「やや悪い」の評価が多いのと、 Q15の理解把握について、「良い」の評価が少なめなのが、効いているか…。 板書については、文字を大きくとか、記載場所の流れを改めて意識してみよう。
情報構造論は、79.8ポイント。あとちょっとで、80点(学生さんなら優)だったのにぃ。 昨年度は、80.9ポイントなので、連続ポイントダウン。 Q4板書のポイントが、これまた低めなので、改めて意識した書き方の必要があるかな。
講義録記事にヒント表示を導入
講義録をBLOGの形で、ページに掲載するのを、この10年ほど続けているけど、 準備が不十分な場合には、授業で過去の記事をプロジェクタで表示しながら説明… という場合もある。
しかし、過去の記事で丁寧に書いてありすぎると、問題の答えまでモロに記事に 書いておくと、記事を読んでいる学生さんが、何も考えないまま…に なってしまう場合が多い。そこで、BLOGのJavaScriptに、 クリック表示/非表示を切り替えられるようなものを埋め込んおくようにした。
// BLOGパーツのJavaScriptに以下を追加 function hint_switch( hs_this ) { // 指定ブロック内の末尾ブロックをinline表示/none非表示をスイッチ if ( hs_this.lastElementChild.style.display == "none" ) { hs_this.lastElementChild.style.display = "inline" ; } else { hs_this.lastElementChild.style.display = "none" ; } }
そして、一時的に非表示にしたい部分には、以下のHTMLを埋め込む。
<div onclick="hint_switch(this)"> <p> // 常に表示しておく部分(ここをクリック) </p> <div style="display: none"> // 一時的に、非表示にしておきたい部分 </div> </div>
変数の寿命とスコープ
先週のC言語の制御構文のシメとして、switch-case文の説明をしてから、 変数の寿命とスコープの説明を行った。
switch-case文の説明では、以下の例は期待通りの動きをしない…といった例も交えて説明。 ただし、double誤差問題や文字列のポインタ関連なので、以後の授業で改めて説明が必要だろう。
// double誤差問題 double x ; for( x = 0.0 ; x <= 1.0 ; x += 0.1 ) switch( x ) { case 0.3 : printf( "A" ) ; // 0.299999...と0.3は違う値になるかも break ; } // 文字列の比較の問題 char str[ 10 ] ; scanf( "%s" , str ) ; switch( str ) { // strの先頭番地と"yes","no"の先頭番地の比較 case "yes" : printf( "はい" ) ; break ; case "no" : printf( "いいえ" ) ; break ; }
変数の寿命とスコープ
最初に、以下の様なプログラムが期待通りに動かない説明をして、 大域変数を共用することの問題を話す。
int i ; // 大域変数(global variable) void foo() { // Aを2回表示 for( i = 0 ; i < 2 ; i++ ) printf( "A" ) ; } void main() { // foo(Aを2回表示)を2回呼び出すつもり for( i = 0 ; i < 2 ; i++ ) foo() ; }
こういったトラブルを避けるためには、局所変数を使えば良い。
局所変数を使って、目的の処理…。改良版はココをクリックで表示。
最近の構造型プログラム言語であれば、 変数には寿命(変数が、作られる/消える、タイミング)と、 スコープ(変数が使える範囲)がある。
#include <stdio.h> // 静的大域変数(スコープ全体,寿命:起動から終了) int x = 123; void foo() { // 動的局所変数(スコープ:foo内部,寿命:foo呼出から戻るまで) int y = 234 ; // 静的局所変数(スコープ:foo内部,寿命:起動から終了) static int z = 345 ; x++ ; y++ ; z++ ; printf( "%d %d %d¥n" , x , y , z ) ; } void main() { foo() ; // 124,235,346が表示 foo() ; // 125,235,347が表示 }
関数の引数
関数の引数の受け渡しの説明。
返り値の型 関数名( 仮引数の宣言 ) { 何らかの処理 ; // 関数に入ると仮引数が局所変数で作られ、 return 式 ; // 実引数が代入される。 } void main() { 関数名( 実引数 ) ; // 実引数は仮引数にコピーされる。 }
値渡し、ポインタ渡しなどの説明をしたいけど、時間なので次週に説明。 残り時間では、BCPL→B言語→C言語(K&R-C→ANSI-C)→C++といった C言語の変遷を簡単に紹介。
処理速度の分析とオーダ記法
今回は、情報処理センターの機種更新に伴うパスワード再発行やら、 授業アンケートの作業に前半の時間をとられ、そのまま演習室にて授業。
2分探索法の処理時間分析
最初に、先週説明の単純サーチ と、2重ループの最大選択法
との比較をしながら、 以前のBLOG資料を使って、 2分探索法の処理時間が
であることを説明する。
オーダ記法
次に、定番の説明であるけれど、 「単純サーチで、100件で1msecかかった。 データ10000件なら何秒かかる?」 同様に、「最大選択法のプログラムで、100件で10msecかかったら、10000件なら何秒?」 という質問から、オーダ記法の導入を説明する。
最後に、 ,
,
といった、Nが大きな値になった時に、式で大きな値となる主要な部分を抜き出したもの がオーダといった説明を行う。
次回の授業での予習ネタとして、以下の式のオーダについて考えておくように…
2015年4月12日(第418回)
- まるよし Train Pops ~ 国語と遊ぼう! 第98便 「最後の授業」 前編
- 入学式について
- 板書に特徴のある先生
担当:稲葉(2EI・MC)、川﨑(2EI)、田中(2B)、中村(教員)
斉藤卒研室の課題
簡単なunix環境での卒研の課題として、サーバに /home/lab15/Sotsu/access.log を 置いておいた。このファイルは、Webサーバでの数日前のアクセス履歴である。 このファイルの中から、2014年卒研のページ "/sotsu/lab14/" を見た人の 人数を数えよ。
(( /home/lab15/Sotsu/access.log )) 192.156.146.101 - - [29/Mar/2015:07:35:46 +0900] "GET /~t-saitoh/exp/h8/sample/h8car/h8-3664.x ....
SQLite3でデータベース
卒研でデータベースを使いたい人もいるようだけど、 MySQLとかまで完璧なのが必要なければ、SQLite を使ったほうが楽。 ただし、データ型は実質すべてtext型になるけど、簡単なアプリベースなら 支障はないはず。
<?php // データ保存用の sqlite-data はあらかじめ作っておく。 // sqlite-data の書き込み許可 // (手抜) $ chmod 777 sqlite-data // (厳密) # chgrp sqlite-data // # chmod 774 sqlite-data // sqlite-data/.htaccess には"Require all denied"を書いて // ディレクトリ内をWeb的にアクセス禁止にする。 // サーバのPHPを使うと、エラーが見つからず苦労するかも // その時は、.htaccess ファイルに、以下の設定を記載しておく // "php_flag display_errors On" // 説明しやすいように実行だけ関数をつくる function exec_command( $db , $cmd ) { if ( ($db->exec( $cmd )) === FALSE ) { print $db->lastErrorMsg() ; } } // データベースを作って初期データを登録 function table_initialize( $db ) { exec_command( $db , "create table Person(name text,phone text) ;" ) ; exec_command( $db , "insert into Person (name,phone) values('t-saitoh','272925');" ) ; exec_command( $db , "insert into Person (name,phone) values('tomoko' ,'123456');" ) ; exec_command( $db , "insert into Person (name,phone) values('mitsuki' ,'234567');" ) ; } // データベースを作る if ( !file_exists( "./sqlite-data/sample.db" ) ) { // なにも無い状態 $db = new SQLite3( "./sqlite-data/sample.db" ) ; table_initialize( $db ) ; } else { // すでに作られている場合 $db = new SQLite3( "./sqlite-data/sample.db" ) ; } ?> <html> <head> </head> <body> <pre> <?php // 登録されているデータを全部表示 if ( ($query = $db->query( "select * from Person" )) !== FALSE ) { while( $res = $query->fetchArray( SQLITE3_NUM ) ) { printf( "| %-10s | %-10s |\n" , $res[0] , $res[1] ) ; } } ?> </pre> </body> </html>
情報構造論ガイダンス
前年度のプログラミング応用の次のステップとしての情報構造論として、 どういった内容を行うのかガイダンスを行う。
最初に、使用する教科書のタイトルにもある、アルゴリズムという言葉の説明として、 アルゴリズムとは、計算の方法の考え方、 そのアルゴリズムをどう表現するのかがパラダイム、 そのパラダイムに沿って実際に書いたものがプログラム。
いいプログラムとは?
次に、ある程度プログラム記述を学んできたところだし「あなたはどうプログラムを書くといいと思うか?」 を次々と聞いてみた。 学生さんから帰ってくる言葉は、 「わかりやすい、行数が短い、関数が使われている、変数名が解りやすい、バグが少ない…」 といった物がほとんど。 中には、「プログラムが再利用しやすい」といったオツな答えもあったけど、 どれも大きくまとめれば「わかりやすい」という観点。
途中で、「処理速度が速い」という答えもあったけど、「メモリの使用量が少ない」という 観点がなかなか出てこない。
処理速度という観点では、3秒ルールなどの雑談を交えながら計算時間について説明。 また、メモリの使用量という観点では、限られた主記憶を有効に使わないと、 プログラムが動かなかったり、仮想記憶などを使うことになり、頻繁なスワップ処理で 処理速度の低下につながることを説明する。
これらの「プログラムの分かりやすさ」、「処理速度」、「メモリの使用量」は、一般的に、 どれかを優先すれば、ほかの観点が悪化してしまうトレードオフの関係にあることを説明。
処理時間を式で表現
まず、プログラムの処理時間を分析するために、簡単なプログラムがどんな式で表現できるかを示す。
// 配列(順序はデタラメ)の中の特定データを探す処理。 int data[ N ] ; for( i = 0 ; i < N ; i++ ) { if ( data[ i ] == key ) break ; }
このようなループ処理であれば、ループ回数の平均を考えて式にすると、
で表現できることを説明。
// 最大選択法の並び替え int data[ N ] ; for( i = 0 ; i < N-1 ; i++ ) { int m = i ; for( j = i+1 ; j < N ; j++ ) { if ( data[m] > data[j] ) m = j ; } tmp = data[ m ] ; data[ m ] = data[ i ] ; data[ i ] = tmp ; }
このような処理であれば、ループ回数をΣなどを用いて表しながら、以下のような式で示されることを説明。
プログラミング応用ガイダンス
プログラミング応用では、どういった内容を扱うのかを最初に説明した後、 最初は2年の復習となることから、C言語の文法のおさらい。 特に制御構文のfor,ifを中心にフローチャートとの対応をとる説明とした。
最初に、簡単なプログラムでの式の実行順序の理解の確認。
// (1) int i ; for( i = 0 ; i < 4 ; i++ ) { if ( (i % 2) == 0 ) { printf( "%d\n" , i ) ; } } // (2) int i , j ; for( i = 0 ; i < 3 ; i++ ) { for( j = 0 ; j < 2 ; j++ ) { printf( "%d\n" , i * j ) ; } }
次に、break文とcontinue文の説明を行う。
// for文 int i ; for( i = 0 ; i < N ; i++ ) { : if ( .... ) break ; if ( .... ) continue ; : } // break , continueの動き i = 0 ; // for初期化 LOOP: if ( i >= N ) goto BREAK ; // for終了判定 : if ( .... ) goto BREAK ; // break(ループ脱出) if ( .... ) goto CONTINUE ; // continue(次の繰返し) : CONTINUE: i++ ; // for繰返し変数更新 goto LOOP ; BREAK: