ホーム » 2009 » 11月 » 10

日別アーカイブ: 2009年11月10日

2009年11月
« 10月   12月 »
1234567
891011121314
15161718192021
22232425262728
2930  

最近の投稿(電子情報)

アーカイブ

カテゴリー

プログラミングパズル

高専プロコンや歯みがきロボコンと、自分の関連するイベントもひとまず終了。 ただ、高専プロコンで課題自由部門の本戦参加ができなかったり、 歯みがきロボコンでもzeroからライントレースを作ったりという、 実践で頼りがいのある学生さんが少ない。

難しいことをああだこうだと指導するよりも、 興味を持って実際にプログラムを書く事が先決だろうと考える。 ゲームを作ってみるのも1つだけど、数値をうまく操る技術がないと、 キャラクターの動きも単調でつまらないはず。 ということで、プログラミングパズルにチャレンジしてもらうのがいいのではないかと考える。問題も極めてシンプルに….

プログラミングパズル

  1. x*yの計算をするプログラムを作成せよ。
    ただし、乗算演算子*や除算演算子/は使わない事。 1000*1000の実行にかかる時間を、他の人のプログラムと比べてみること。
  2. 上記のプログラムを、for,while,do-while,goto文を使わずに記述せよ。
  3. 99の階乗(99!)を全ての桁を計算せよ。
    ただし、言語付属のBIGNUM系パッケージは使わない事。
99の階乗は、Common Lispであれば、勝手にBIGNUMを使ってくれるので、
→ (defun fact(n)
(if (= n 0) 1 (* n (fact (- n 1)))))
→ (fact 99)
933262154439441526816992388562667004907
159682643816214685929638952175999932299
156089414639761565182862536979208272237
582511852109168640000000000000000000000
でも、BIGNUM相当を自分ですらすら書けて、普通のプログラマー。

ワード境界とビットフィールド

構造体の説明の後半として、メモリの使用量と関係深いワード境界とビットフィールドの説明を行う。 最初に、主記憶の不足とプログラムの関係として、仮想メモリとメモリ不足時にハードディスクアクセスが多発し、スピード低下について述べる。

ワード境界

struct A {
   char name[ 3 ] ; // イニシャルと点数の構造体?
   int  point ;
} a[ 4 ] ;
境界無視 境界配置
|NNNP|   |NNNx|    N:name
|PPPN|   |PPPP|    P:point
|NNPP|   |NNNx|
|PPNN|   |PPPP|
|NPPP|   |NNNx|
|PNNN|   |PPPP|
|PPPP|   |NNNx|
|PPPP|

CPUに比べて、主記憶の速度は遅いため、メモリアクセスは必要最小限にしたい。 しかしながらワード境界を無視すると、a[0].point の取得には、2回のメモリアクセスが 発生するため、処理速度が低下する場合がある。 このため、name 3文字の後ろに1byteの空きを設けて、ワード境界をまたがらない様に 構造体の要素を配置するのが一般的。

この話の前に、char=8bit=1byte=0..255(-128..0..127),32bitCPUなら、 int=32bit=4byte=-2^31..0..2^31-1といった復習を簡単に行った。

メモリインタリーブとよばれる方式を使うと、 ワード境界があっても最小限のメモリ参照で済むが、ハードウェアが複雑化する。 情報処理技術者試験を受けるのであれば、インターリーブも理解しておくこと。

ビットフィールド

struct YMD {
   int  year ;
   int  month ;
   int  day ;
} ;

といった構造体では、12byte のメモリを使用するけど、メモリ使用を減らすには、 year=0..2047,month=0..15,day=0..31と考えれば、20bitで十分。 メモリの使用量を減らすために、year , month , day を1つのint型で覚えるには?

ymd = year *10000 + month*100 + day ;
printf( "月=%d" , (ymd % 10000) / 100 ) ;

という方法もあるけど、2進数として年月日を覚えるのであれば、

// YYYYYYYYYYY000000000
// or         MMMM00000
// or             DDDDD
ymd = (year << 9) | (month << 5) | day ;
printf( "年=%d" , ymd >> 9 ) ;
printf( "月=%d" , (ymd >> 5) & 0x0F ) ;
printf( "日=%d" , ymd & 0x1F ) ;

とすれば、int 型で、年月日を必要最小限のbit数で保存できる。 しかしながら、2進数演算は分かりにくいので、以下のようなビットフィールドを使えば簡単。

struct YMD {
   unsigned int  year  : 11 ;
   unsigned int  month :  4 ;
   unsigned int  day   :  5 ;
} ;