2

これについては、c# チャットで継続的な議論が行われています。元の質問はこれでした:

たとえば (Int32) 5+5 は 1234723847+32489237 よりも速く計算されますか?

私の最初の考えは、パディング ゼロを無視するためにバイナリ レベルで最適化が行われるので、数値が小さいほど高速になるというものでした。

それで、私はそれをテストしました。興味のある方はこちらのプログラムをどうぞ。そうでない場合は、結果にスキップしてください。

Stopwatch sw = new Stopwatch();
Int64 c = 0;
long msDifferential = 0;     //
int reps = 10; //number of times to run the entire program
for (int j = 0; j < reps; j++)
{            
    sw.Start();  //                
    sw.Stop();   // Just in case there's any kind of overhead for the first Start()
    sw.Reset();  //

    sw.Start();  //One hundred million additions of "small" numbers
    for (Int64 i = 0, k = 1; i < 100000000; i++, k++)
    {   
        c = i + k;
    }
    sw.Stop();

    long tickssmall = sw.ElapsedTicks;       
    long mssmall = sw.ElapsedMilliseconds;

    sw.Reset();

    sw.Start();  //One hundred million additions of "big" numbers
    for (Int64 i = 100000000000000000, k = 100000000000000001; i < 100000000100000000; i++, k++)
    {
        c = i + k;
    }
    sw.Stop();

    long ticksbig = sw.ElapsedTicks;
    long msbig = sw.ElapsedMilliseconds;

    //total differentials for additions
    ticksDifferential += ticksbig - tickssmall;   
    msDifferential += msbig - mssmall;                
}

//average differentials per 100000000 additions
long averageDifferentialTicks = ticksDifferential / reps;
long averageDifferentialMs = msDifferential / reps;

//average differentials per addition
long unitAverageDifferentialTicks = averageDifferentialTicks / 100000000;
long unitAverageDifferentialMs = averageDifferentialMs / 100000000;

System.IO.File.AppendAllText(@"C:\Users\phillip.schmidt\My Documents\AdditionTimer.txt", "Average Differential (Ticks): " + unitAverageDifferentialTicks.ToString() + ", ");
System.IO.File.AppendAllText(@"C:\Users\phillip.schmidt\My Documents\AdditionTimer.txt", "Average Differential (Milliseconds): " + unitAverageDifferentialMs.ToString());

結果

デバッグモード

  • 平均単位差: 2.17 ナノ秒

リリース モード (最適化有効)

  • 平均単位差分: 0.001 ナノ秒

リリース モード (最適化無効)

  • 平均単位差分: 0.01 ナノ秒

したがって、デバッグ モードでは、「大きい」数値は、「小さい」数値よりも加算ごとに合計するのに約 2.17 ナノ秒長くかかります。ただし、リリース モードでは、違いはほとんどありません。


質問

そのため、いくつかのフォローアップの質問がありました。

  1. 私の目的にはどのモードが最も正確ですか? (デバッグ、リリース、リリース(オプトなし))
  2. 私の結果は正確ですか?もしそうなら、速度の違いの原因は何ですか?
  3. デバッグモードの違いがこれほど大きいのはなぜですか?
  4. 他に考慮すべきことはありますか?
4

1 に答える 1

2

特定の最適化の効果は、コンパイラによって異なります。それぞれのケースで生成されたアセンブリ コードを確認し、生成された CPU 命令を比較する必要があります。CPU のレベルでは、同じ命令が生成された場合、追加する値に応じてパフォーマンスに違いはないはずです。CPU にはクロック信号があり、同じ命令が同じサイズのオペランドで実行される場合、オペランドのビットが 1 か 0 かに関係なく、単純な算術演算は同じ数のクロック ティックを使用します。メモリの影響はパフォーマンスに影響を与える可能性がありますが、ここではデータが十分に小さいため、おそらくそれほど問題にはなりません。逆アセンブルでは、変数がレジスタに格納されるかどうかを確認できます。そうでない場合は、大きなデータで重要な役割を果たす (キャッシュ ヒット/ミス、物理メモリ アクセスなど) いくつかの変数の影響もここで重要なのかどうか疑問に思うかもしれません。CPU は 1 秒あたり数十億回の算術演算が可能ですが、RAM は外部デバイスであり、はるかに低速です。とにかく、そのような効果はランダムであり、追加する値が大きいか小さいかに依存しません。パイプラインのストール、命令の並べ替えなどについても同様です。異なる時間に実行された一連の実験では、平均時間は誤差の範囲内で同じである必要があります (リリース モードで得られる差は確かにこのカテゴリに分類されます)。CPU は毎秒数十億回の算術演算が可能ですが、RAM ははるかに遅い外部デバイスです。とにかく、そのような効果はランダムであり、追加する値が大きいか小さいかに依存しません。パイプラインのストール、命令の並べ替えなどについても同様です。異なる時間に実行された一連の実験では、平均時間は誤差の範囲内で同じである必要があります (リリース モードで得られる差は確かにこのカテゴリに分類されます)。CPU は毎秒数十億回の算術演算が可能ですが、RAM ははるかに遅い外部デバイスです。とにかく、そのような効果はランダムであり、追加する値が大きいか小さいかに依存しません。パイプラインのストール、命令の並べ替えなどについても同様です。異なる時間に実行された一連の実験では、平均時間は誤差の範囲内で同じである必要があります (リリース モードで得られる差は確かにこのカテゴリに分類されます)。

違いがある可能性があると思われる1つの可能性は、64ビット命令によって直接ではなく、複数の32ビット命令を使用して64ビット数値を処理するコンパイラです。このような場合、スマート コンパイラは、一部のループで使用する値が 32 ビット数の制限を超えて大きくなることはないと判断し、2 つの 32 ビット値ではなく、1 つの 32 ビット値に対してのみ機能する命令を発行する可能性があります。 64 ビット値。それが事実であるかどうかは、分解を見ると明らかになる可能性があります。

于 2012-09-13T17:32:23.463 に答える