2013/08/28

5分ごとにベルを鳴らして

 「1から10まで足してくれ」という作業は比較的簡単にプログラムで書いてコンピュータにやってもらうことが出来るけど、「5分ごとにベルを鳴らして」ってのは簡単な作業だけどコンピュータでも分かるように書くのは??

 簡単そうだけど、、まず現在の時間を記録して、無限ループに入り、「もし、5分過ぎてたら、ベルを鳴らす」というプログラムを書きそうじゃない?それではCPUがホットプレートみたくなっちゃう。ぶっちゃけプログラムとしては間違ってないと思うがコンピュータはまじめすぎるので、こう書くと5分過ぎるまで1秒間に何千万回(最新のCPUならもっともっとたくさん)も時間をチェックしようとしてパンクしちゃう。
 正しくは無限ループの中で「もし、5分過ぎてたらベルを鳴らす、んで、まぁ、5分たってなかったら1秒くらい休んでていいよ、どうせ5分1秒でも誰も気にしないし」と教えてやんないとダメ。これは「無限ループにはsleep(休憩)が必要」って知ってるのと「5分ごとにベルを鳴らす」のに加えて「5分1秒でも良い」と決めないといけないことだ。「ずれて良いのは100分の1秒まで」ってんなら「100分の1秒だけ休んでいい」に変わるだけだ。てかね「5分ごとにベルを鳴らして」っていう課題に対して「5分1秒でも良いですか?」なんて聞くのは馬鹿げてるよね(どうせ研究発表のベル鳴らしとかを自動でやりたかっただけでしょ)。だからプログラマが勝手に仕様書に無い仕様を作りこんじゃうんだよね。で出来上がったものを見せて「ベルの間隔が1秒ずれるんだけど!」って怒られるんだよね。実は「100分の1秒だけ休んでいい」に変えてもそんなに変わんないし、、、この場合、コンピュータに楽をさせようと1秒も休ませちゃったプログラマが悪いってことになりがちだし。。でもプログラマはなぜかコンピュータに楽させようと考えるんだよね。その方が効率的で速いプログラムってことだからね。ほんとは「誤差100分の1秒まで」ってのを要求に入れなかったのも悪いんだよ。そうすりゃプログラマはコンピュータに楽させつつ誤差100分の1秒のプログラムを考える分けだ。つまり、「5分までまだまだある」なら「1秒くらい休んで良いよ(5秒くらい休ませても良いかもしれない)」で「もうすぐ5分だ」となったら100分の1秒に1回のペースでチェックさせるんだ。実は人間も無意識にこうやってるよね(きっと)。これは「1秒休む」のに比べたら複雑なプログラムだけどね。

(この問題、いきなり300秒休んでからベルを鳴らす、にしたらどうなるんだろう?多分、sleepっていう関数はあまり正確じゃないんで、コンピュータの時間を取得するAPIを使った方が正確に5分測れるって感じだと思う。もちろんコンピュータの時計以上に正確ではないけど。)
(「1から10まで足す」というのはプログラム的には普通はfor文使って書くけど、「((1+10)*10)/2」という公式があるよね。
こういう最適化するとプログラムが柔軟じゃなくなっちゃうけど、こういうことが出来るって覚えておくのは悪くない。)

VC++版、5分ごとに「Bell.mp3」を鳴らすプログラム。mciSendStringって面白いね。プログラムの中でコマンド叩いてるみたい。
#include <tchar.h>
#include <windows.h>
#include <mmsystem.h>
 
int _tmain(int argc, _TCHAR* argv[])
{
   mciSendString(L"stop all"NULL, 0, NULL);
   DWORD startT = GetTickCount();
 
   while(true) {
      DWORD currentT = GetTickCount();
      if(currentT - startT >= 300000){
         mciSendString(L"open Bell.mp3 type mpegvideo alias Bell",
            NULL, 0, NULL);
         mciSendString(L"play Bell from 0"NULL, 0, NULL);
         startT = currentT;
      }
      Sleep(1000);
   }
 
   mciSendString(L"close Bell"NULL, 0, NULL);
   return 0;
}
startT と currentTの差によってSleep間隔を調整する、なんてしないでも十分。

0 件のコメント:

コメントを投稿