私は単純な素数生成ワンライナーを Scala から C# に適応させていました (このブログの著者によるコメントで言及されています)。私は次のことを思いつきました:
int NextPrime(int from)
{
while(true)
{
n++;
if (!Enumerable.Range(2, (int)Math.Sqrt(n) - 1).Any((i) => n % i == 0))
return n;
}
}
動作し、ブログで参照されているコードを実行した場合と同じ結果が返されます。実際、それはかなり速く動作します。LinqPad では、約 1 秒で 100,000 番目の素数を生成しました。好奇心から、 and なしEnumerable.Range()
で書き直しましたAny()
:
int NextPrimeB(int from)
{
while(true)
{
n++;
bool hasFactor = false;
for (int i = 2; i <= (int)Math.Sqrt(n); i++)
{
if (n % i == 0) hasFactor = true;
}
if (!hasFactor) return n;
}
}
直感的には、同じ速度で実行されるか、後者の方が少し速く実行されることを期待します。実際には、同じ値 (100,000 番目の素数) を 2 番目の方法で計算すると、12 秒かかります。これは驚異的な違いです。
それで、ここで何が起こっているのですか?2 番目のアプローチでは、CPU サイクルを食い尽くす余分な何かが根本的に起こっているか、Linq の例のバックグラウンドで何らかの最適化が行われているに違いありません。理由を知っている人はいますか?