わかりました、まず第一に、コンパイラがこれを自動的に行う方法がわかりません。そして、コンパイラーが選択しなければならないアルゴリズムは、数百とまではいかなくても、少なくとも 10 はあると確信しています。
とにかく、それはおそらくコンパイラ固有です。
しかし、その有効性を計算するお手伝いをすることができます。
通常、この手法ではパフォーマンスが大幅に向上するわけではないことに注意してください。
しかし、ループ計算が繰り返されると、高いパーセンテージのパフォーマンスが得られます。
これは、通常、ループ内の関数がループの条件チェックよりもはるかに多くの計算時間を要するためです。
ですから、定数を使った単純なループがあるとしましょう。これは、怠惰すぎてコピー アンド ペーストを行うことができなかったか、単に見栄えが良くなると思ったからです。
for (int i = 0; i < 5; i++)
{
DoSomething();
}
ここでは、 5 つの int 比較、5 つのインクリメント、および5 つのDoSomethig() 呼び出しがあります。
したがって、DoSomething() が比較的高速である場合、15 回の操作が行われます。
これをアンロールすると、たった 5 つの操作に減らすことができます。
DoSomething();
DoSomething();
DoSomething();
DoSomething();
DoSomething();
定数を使用すると簡単なので、変数を使用してどのように機能するかを見てみましょう。
for (int i = 0; i < n; i++)
{
DoSomething();
}
ここでは、n回の int 比較、n回のインクリメント、およびn回のDoSomethig() 呼び出し = 3nがあります。ここで、完全に展開することはできませんが、一定の係数で展開することはできます ( nが大きくなると予想されるほど、より多く展開する必要があります)。
int i;
for (i = 0; i < n; i = i+3)
{
DoSomething();
DoSomething();
DoSomething();
}
if (i - n == 2)
{
DoSomething(); // We passed n by to, so there's one more left
}
else if (i - n == 1)
{
DoSomething(); //We passed n by only 1, so there's two more left
DoSomething();
}
ここでは、n/3+2の int 比較、n/3のインクリメント、n回のDoSomethig() 呼び出し = (1 2/3)*nがあります。(1 1/3)*nオペレーション
を節約できました。これにより、計算時間がほぼ半分に短縮されます。
参考までに、別の巧妙なアンロール手法は、ダフのデバイスと呼ばれます。
しかし、それは非常にコンパイラと言語の実装に固有です。これが実際にはさらに悪い言語があります。