こんにちは。
開発部の植草です。

前回、ループアンローリングについて説明しましたが、

実際にプログラムを書いてみた方はいますでしょうか?
実際にループアンローリングのプログラムを書いていて気が付いた人もいるかと思いますが
端数があるときには使えないんですよね。

10段のループアンローリングをやる場合
loop = 100;
sum = 0;
for(i=0;i<loop;i+=10){
    sum += i;
    sum += i+1;
    sum += i+2;
    sum += i+3;
    sum += i+4;
    sum += i+5;
    sum += i+6;
    sum += i+7;
    sum += i+8;
    sum += i+9;
}

になるわけですが、これはiが100回(10の倍数回)ループするから可能で
これが108回のループの場合は端数が出てしまいます。

ではどうすれば良いかというと
10段の場合を例にします。
for(i=0;i<(loop%10);i++){
    sum += i;
}
for(i;i<loop;i+=10){
    sum += i;
    sum += i+1;
    sum += i+2;
    sum += i+3;
    sum += i+4;
    sum += i+5;
    sum += i+6;
    sum += i+7;
    sum += i+8;
    sum += i+9;
}

となります。

要はループの回数に対して、n段のループ展開のnで割ったあまりだけ
別途計算してあげればいいんですよね。
例では先にやりましたが、条件の書き方次第では最後にやることも可能です。


もちろん、こんなループアンローリングは
100回やそこらのループでは恩恵を受けることはでないですし、
コード量も増えるので面倒なだけです。

こういうのは科学計算などのループの回数が10万とか100万回とか
ループを繰り返す際には非常に有効になります。

またループを展開するのは非常に有効ですが、
コード量が増えるためメモリの使用量も増えます。
今はハードウェアが進歩しているためメモリが足りないとか中々無いでしょうが
メモリ(厳密にはキャッシュ)を超えるような場合は
キャッシュミスのペナルティが大きくなり、あまり効果が得られないことも懸念されますのでご注意!!

次回は実際のループアンローリングの高速化について検証してみたいと思います。