ホーム » t-saitoh の投稿

作者アーカイブ: t-saitoh

2018年8月
« 7月    
 1234
567891011
12131415161718
19202122232425
262728293031  

最近の投稿(電子情報)

アーカイブ

カテゴリー

PCN武生のお手伝い

今日はPCN武生の最初の講座。
小学校の一年生で、簡単な命令と早押しゲームの体験でした。

緊急連絡システムのOS更新など

緊急連絡システムのOSが、Ubuntu/trusty でそろそろ、サポート期間に近づいているので、OS の更新を行った。

Ubuntu 更新

更新自体は、do-release-upgrade コマンドで、xenial に更新が進む。

$ sudo do-release-upgrade

しかしながら、openssh-server が、更新でエラーがでて、かなり悩んだ。解ってみれば、単純なミスで、自作の /etc/init.d/script を書いてあったけど、その insserv ヘッダで、ssh をコピーしてヘッダ部の # Provides: sshd の行を書き換えてなかった。

このおかげで、insserv が、ssh はすでに登録されている…と勘違いしていた。

緊急連絡システムの文字コードUTF-8 に変更

Ubuntu の更新をかけたら、php5 が使えなくなったため、php7.0 に更新を行うが、これに合わせ、取り扱い文字コードを EUC-JP から UTF-8 に変更を行った。

緊急連絡システムは、内部でデータベースを利用せず、テキストファイルですべてを管理しているが、最初は利用組織毎の設定ファイルや、データファイルをエディタでチマチマと修正を始めたけど、大量の組織のため、途中で断念。perl でファイル名や記載時のエンコーディングを修正するスクリプトを書いて一発変換。

あとは、プログラム中のエンコーディング依存の部分を修正し、送信できることを確認してひとまず移行作業完了。

情報構造論の追試のための解答例

情報構造論の成績不振者のための追試を、8/9(木) 15:30 より 4EI 教室で実施します。
インターンシップなどで当日参加困難な場合は、別日に実施しますので、連絡してください。
テスト問題の解答および解説を、以下に示します。

ex2018-4-2-ans

追試では、問題を変更して出題しますので、決して文字の暗記で臨まないこと。

局所変数配列をreturn

情報構造論の前期期末試験で、局所変数返しの解答が多かったので、メモ。

JavaScript でプログラムを書いていると、動くネタだけど、C言語では初心者がよく間違って書いてしまう定番であり、それなりに動いたりするから、誤解が増えてしまう可能性もある。

char* foo() {
   char str[ 20 ] ;
   strcpy( str , "Hello World" ) ;
   return str ;
}
char* bar() {
   char baz[ 20 ] ;
   memset( baz , 'A' , sizeof( baz ) ) ;
   return NULL ;
}
void main() {
   char* ans = foo() ;
   printf( "%s¥n" , ans ) ; // Hello World
   // 一見正しく動いているように思うかも。

   bar() ; // 局所変数を触るだけの処理
   printf( "%s¥n" , ans ) ; // AAAAAAAAAAA
   // ans の中身が壊れている。
}

電子情報キャンパスツアー2018

ロボット制御系


認知科学系展示


数値シミュレーション系

プロジェクションマッピング

自室サーバ、やばいかな

自室のサーバ、OS 更新をかけて部屋を離れていたら、どうも気絶をしていたようだ。

パワーリセットをかけても起動をしないので、モニタをつないで確認したら、リカバー時の fsck がうまくいっていない様子。”(initramfs)”のプロンプトの出ている状態で、fsck /dev/sda1 を入力し、いくらかエラーを吐きながらもなんとか FIX は終了し、再起動をかけたら、これまた起動せず。

boot初期段階で、”unreliable CPU thermal sensor monitoring disabled”で止まってる。色々と対策をしらべていたら、なぜか起動処理が再開され、ひとまず復帰。

unreliable CPU thermal sensor monitoring disabled

でも、これはいつ再発してもおかしくない…。自室のサーバは “PowerEdge T105” で、これのカタログを拾うと 2007年の製品。ひとまず起動したマシンで /etc のファイルの最古参の日付を確認すると、2008年。ほぼ 10 年間使っていたのか。

エラーメッセージからすれば、「CPUの温度センサーが怪しい」とか、マザーボード故障の可能性が高い。こりゃ、次のサーバを準備すべきだな。

実数と整数の変換

情報制御基礎で出題した問題で、5点の移動平均の処理の一部に、以下のコードがあった場合の間違い説明の問題。

int avg() {
   int s = .... ;
   return (1/5) * s ;
}

の間違いを修正せよ….の答えだけど、return 0.2 * s ; とか return s/5 ; が答えだけど、小数点以下が切り捨てになるのか、四捨五入になるのか気になってきた。

for( double x = 0.0 ; x <= 2.0 ; x += 0.1 )
   printf( "%ld %d\n" , x , (int)x ) ;

で確認してみたら、(int)実数は、小数点以下切り捨てだな。となると、四捨五入したいなら、return (int)( 0.2 * s + 0.5 ) ; とか、return (s+2)/5 ; とか書いてほしい…とか微妙な話になるな。

採点は、切り捨て・四捨五入の誤差については問わないで、0.2*s , s/5 を◯でいこう。

情報制御基礎の超優秀レポート

3年の学際科目で、5学科入り乱れての参加のある「情報制御基礎」の科目。幅広い知識を習得してもらう目的ということで、簡単なレポートでも要件を満たしていればA評価、B評価としているが、電気電子の学生さんからオリジナリティあふれる取り組みや、きちんとした考察のレポートがいくつか出てきている。この学生のレポートを100%としたら、よくわからないけど頑張ってついてきている学生さんが厳しくなっちゃうなぁ。

ひとまず嬉しいレポートもらったので、メモメモ。

澤井先生を偲ぶ

昨日、公私ともに大変お世話になった澤井先生がお亡くなりになったとの連絡が入った。私が高専に入ってプログラミングにのめり込み、就職の際に高専に誘って頂いた。

仕事でも、色々と迷惑をかけ、大変世話になっていた。

4月ころに退官する先生へのOB会の勧誘で来られている際にお会いしたけど、肺疾患の酸素ボンベを持ち歩いていて、体調も良くなかった様だった。

澤井先生は、福井高専の発足当初から電気科で教えられていて、コンピュータの発達と共に、プログラミング、計算機構成論といった授業を担当し、澤井先生にFORTRANを習い、AND-OR,JK-FFで頭をパンクさせた人も数多いことでしょう。そして、電子情報工学科設立と共に学科を移り、数多い「電子情報卒業生」を送り出してくれた先生でした…。

集合とリスト処理

リスト構造は、必要に応じてメモリを確保するデータ構造であり、データ件数に依存しないプログラム が記述できる。その応用として、集合処理を考えてみる。

2進数を用いた集合計算

リストによる集合の前に、もっと簡単な集合処理を考える。データ件数の上限が少ない場合には、「2進数の列」の各ビットを集合の各要素に対応づけし、要素の有無を0/1で表現する。この方法を用いるとC言語のビット演算命令で 和集合、積集合を計算できるので、処理が極めて簡単になる。

以下のプログラムは、0〜31の数字を2進数の各ビットに対応付けし、 ba = {1,2,3} , bb = {2,4,6} , bc= {4,6,9} を要素として持つ集合で、ba ∩ bb , bb ∩ bc の計算を行う例である。

void bit_print( unsigned int x ) {
   for( int i = 0 ; i < 32 ; i++ )
      if ( (x & (1 << i)) != 0 )
         printf( "%d " , i ) ;
   printf( "\n" ) ;
}
void main() {     // 98,7654,3210
   // ba = {1,2,3} = 00,0000,1110
   unsigned int ba = (1<<1) | (1<<2) | (1<<3) ;
   // bb = {2,4,6} = 00,0101,0100
   unsigned int bb = (1<<2) | (1<<4) | (1<<6) ;
   // bc = {4,6,9} = 10,0101,0000
   unsigned int bc = (1<<4) | (1<<6) | (1<<9) ;

   bit_print( ba & bb ) ; // ba ∩ bb = {2}                 
   bit_print( bb & bc ) ; // bb ∩ bc = {4,6}
   bit_print( ba | bc ) ; // ba ∪ bc = {1,2,3,4,6,9}
}

このような、2進数を用いた処理で有名なものとして、エラトステネスのふるいによる素数計算がある。このアルゴリズムでは、各bitを整数に対応付けし、素数で無いと判断した2進数の各桁に1の目印をつけていく方式である。

unsigned int prime = 0 ;
void filter() {
   for( int i = 2 ; i < 32 ; i++ ) {
      if ( (prime & (1 << i)) == 0 ) {
         // iの倍数には、非素数の目印をつける
         for( int j = 2*i ; j < 32 ; j += i )
            prime |= (1 << j) ;
      }
   }
   for( int i = 2 ; i < 32 ; i++ ) {
      // 目印のついていない数は素数
      if ( (prime & (1 << i)) == 0 )
         printf( "%d\n" , i ) ;
   }
}

リスト処理による積集合

前述の方法は、リストに含まれる/含まれないを、2進数の0/1で表現する方式である。しかし、2進数であれば、unsigned int で 32要素、unsigned long long int で 64 要素が上限となってしまう。 (32bitコンピュータ,gccの場合)

しかし、リスト構造であれば、リストの要素として扱うことで、要素件数は自由に扱える。また、今までの授業で説明してきた cons() などを使って表現すれば、簡単なプログラムでリストの処理が記述できる。

// 先週までに説明してきたリスト構造と補助関数
struct List {
   int     data ;
   struct List* next ;
} ;
struct List* cons( int x , struct List* n ) {
   struct List* ans ;
   ans = (struct List*)malloc( sizeof( struct List ) ) ;
   if ( ans != NULL ) {
      ans->data = x ;
      ans->next = n ;
   }
   return ans ;
}
void print( struct List* p ) {
   for( ; p != NULL ; p = p->next ) {
      printf( "%d " , p->data ) ;
   }
   printf( "\n" ) ;
}
int find( struct List* p , int key ) {
   for( ; p != NULL ; p = p->next )
      if ( p->data == key )
         return 1 ;
   return 0 ;
}

例えば、積集合(a ∩ b)を求めるのであれば、リストa の各要素が、リストb の中に含まれるか find 関数でチェックし、 両方に含まれたものだけを、ans に加えていく…という考えでプログラムを作ると以下のようになる。

// 集合積の計算
struct List* set_prod( struct List* a , struct List* b ) {
   struct List* ans = NULL ;
   for( ; a != NULL ; a = a->next ) {
      // aの要素がbにも含まれていたら、ansに加える
      if ( find( b , a->data ) )
         ans = cons( a->data , ans ) ;
   }
   return ans ;
}
void main() {
   struct List* a = cons( 1, cons( 2, cons( 3, NULL ) ) ) ;
   struct List* b = cons( 2, cons( 4, cons( 6, NULL ) ) ) ;
   struct List* c = cons( 4, cons( 6, cons( 9, NULL ) ) ) ;
   print( set_prod( a , b ) ) ;
   print( set_prod( b , c ) ) ;
}

例題として、和集合差集合などを考えてみよう。

リストの共有と削除の問題

リスト処理では、mallocを使うが、メモリリークをさせないためには、使用後のリストの廃棄は重要である。リストの全要素を捨てる処理であれば、以下のようになるであろう。

void list_free( struct List* p ) {
   while( p != NULL ) {
      struct List* d = p ;
      p = p->next ;
      free( d ) ; // 順序に注意
   }
}

一方、前説明の和集合(a ∪ b)のプログラムを以下のように作った場合、list_freeの処理は問題となる。

// 集合和
struct List* set_union( struct List*a, struct List*b ) {
   struct List* ans = b ;
   for( ; a != NULL ; a = a->next )
      if ( !find( b , a->data ) )
         ans = cons( a->data , ans ) ;
   return ans ;
}
void main() {
   struct List*a = cons( 1, cons( 2, cons( 3, NULL ) ) ) ;
   struct List*b = cons( 2, cons( 3, cons( 4, NULL ) ) ) ;
   struct List*c = set_union( a , b ) ;
   // a,b,cを使った処理
   // 処理が終わったので、a,b,cを捨てる
   list_free( a ) ;
   list_free( b ) ;
   list_free( c ) ;
   // c = { 1 , (bのリスト) }
   // (b)の部分は先のlist_free(b)で解放済み
}

このような、リストb,リストcで共有されている部分があると、データの廃棄処理をどのように記述すべきなのか、問題となる。

これらの解決方法としては、(1) set_union() の最初で、ans=b となっている部分を別にコピーしておく、(2) 参照カウンタ法を用いる、(3) ガベージコレクタのある言語を用いる…などがある。(2),(3)は後期授業で改めて解説を行う。

struct List* copy( struct List*p ) {
   struct List*ans = NULL ;
   for( ; p != NULL ; p = p->next )
      ans = cons( p->data , ans ) ;
   return ans ;
}
struct List* set_union( struct List*a, struct List* b ) {
   struct List* ans = copy( b ) ;
    :
}