2005年09月13日

Duff's device

プログラマー、もしくはソフトウェアエンジニアにしか分からない話。

ここ数日、プログラミング上の一般的なトピックについて話し合う機会があった。いにしえのCの世界で、短い回数のループ処理に時間がかかりすぎる場合、どうすれば高速化できるか?gotoはどういうときに善で、どういう使い方が悪か?swich文の中でのcase文のフォールスルーはあったほうがいいか、ないほうがいいか?などなど。

まさかこの話を全てカバーするコードがあるとは思いもよらなかった。しかもかなり有名らしい。初出は20年も前か…。

ちなみに、上の質問の答え(の一例)は、ループ内の処理をベタに繰り返し書いてしまって、ループを外すか、ループ回数を減らす(例えば4回同じ処理を繰り返し書いて、ループ回数を1/4にする)。多重ループの中から一気に抜けるためのgotoは悪いとは言い切れないが、ループ外からループ内に飛んでくるgotoはほぼ確実に悪い(という説がある)。フォールスルーについては、賛否両論。否定派が優勢か。

そして、以下のコードが Duff's device. 元々ループ処理が遅かったのでループ回数を1/8にして高速化しようとし、でもそうすると処理回数を8で割った「あまりの回数文の処理」がめんどくさくなるので、何とか上手く出来ないかとやってみたらこうなったらしい。もちろんコンパイル出来るし、きちんと動作する。本人による説明つきのページはこちら

send(to, from, count)
register short *to, *from;
register count;
{
  register n=(count+7)/8;
    switch(count%8){
      case 0: do{ *to = *from++;
      case 7:     *to = *from++;
      case 6:     *to = *from++;
      case 5:     *to = *from++;
      case 4:     *to = *from++;
      case 3:     *to = *from++;
      case 2:     *to = *from++;
      case 1:     *to = *from++;
              } while(--n>0);
  }
}

すげえ。でも考えてみると確かに、caseは殆どラベルと一緒だし、do-while内にラベルがあるのも、switchブロックの中にループがあるのもなんら違法ではない。ちなみに、*to に ++ がついていないのは間違いではない。メモリコピーをしているわけではなく、IOレジスタに書き込んでいるらしい。

検索してみると色々なページで色々な説明と共に紹介されている。Cはデフォルトではcase文のフォールスルーをサポートしているが、それについてのDuffのコメントがなかなか良い。

“This code forms some sort of argument in that debate, but I'm not sure whether it's for or against.”

Trackback on "Duff's device"

以下1件のトラックバックはこのページのエントリー"Duff's device"を参照しています。

このエントリーのトラックバックURL: 

» Duff's Device

  • 2005年09月15日 00:28
  • from Cagylogic

非常に珍しい書き方をしたCのコードを見た。その名もDuff's Device。... [続きを読む]

Comment on "Duff's device"

"Duff's device"へのコメントはまだありません。

Post a Comment

コメントする
(HTMLタグは使用できません)
ブラウザに投稿者情報を登録しますか?(Cookieを使用します。次回書き込み時に便利です。)
  •  
  •