3

これらのメソッド呼び出しの最後の3つは、約 最初の4つの時間の2倍。

唯一の違いは、それらの引数が整数に収まらないことです。しかし、これは重要ですか?パラメータはlongとして宣言されているため、とにかく計算にはlongを使用する必要があります。モジュロ演算は、numbers> maxintに対して別のアルゴリズムを使用しますか?

私はamdathlon643200 +、winxp sp3、vs2008を使用しています。

       Stopwatch sw = new Stopwatch();
       TestLong(sw, int.MaxValue - 3l);
       TestLong(sw, int.MaxValue - 2l);
       TestLong(sw, int.MaxValue - 1l);
       TestLong(sw, int.MaxValue);
       TestLong(sw, int.MaxValue + 1l);
       TestLong(sw, int.MaxValue + 2l);
       TestLong(sw, int.MaxValue + 3l);
       Console.ReadLine();

    static void TestLong(Stopwatch sw, long num)
    {
        long n = 0;
        sw.Reset();
        sw.Start();
        for (long i = 3; i < 20000000; i++)
        {
            n += num % i;
        }
        sw.Stop();
        Console.WriteLine(sw.Elapsed);            
    }

編集: 私は今Cで同じことを試しましたが、ここでは問題は発生しませ。すべてのモジュロ演算は、最適化をオンにした場合とオンにしない場合のリリースとデバッグモードで同時にかかります。

#include "stdafx.h"
#include "time.h"
#include "limits.h"

static void TestLong(long long num)
{
    long long n = 0;

    clock_t t = clock();
    for (long long i = 3; i < 20000000LL*100; i++)
    {
        n += num % i;
    }

    printf("%d - %lld\n", clock()-t, n);  
}

int main()
{
    printf("%i %i %i %i\n\n", sizeof (int), sizeof(long), sizeof(long long), sizeof(void*));

    TestLong(3);
    TestLong(10);
    TestLong(131);
    TestLong(INT_MAX - 1L);
    TestLong(UINT_MAX +1LL);
    TestLong(INT_MAX + 1LL);
    TestLong(LLONG_MAX-1LL);

    getchar();
    return 0;
}

EDIT2:

素晴らしい提案をありがとう。.netとc(デバッグモードとリリースモードの両方)は、余りを計算するためにアトミックにcpu命令を使用しませんが、関数を呼び出します。

cプログラムでは、「_allrem」という名前を取得できました。また、このファイルの完全なソースコメントが表示されたため、このアルゴリズムは、.netアプリケーションの場合のように、被除数ではなく32ビット除数を特別に使用するという情報を見つけました。

また、cプログラムのパフォーマンスは、除数の値によってのみ影響を受け、被除数には影響されないこともわかりました。別のテストでは、.netプログラムの剰余関数のパフォーマンスは、被除数と除数の両方に依存することが示されました。

ところで:long long値の単純な加算でさえ、連続するaddおよびadc命令によって計算されます。したがって、私のプロセッサが自分自身を64ビットと呼んでも、実際にはそうではありません:(

EDIT3:

VisualStudio2010でコンパイルされたWindows7x64エディションでcアプリを実行しました。面白いことに、(アセンブリソースを確認した)真の64ビット命令が使用されていますが、パフォーマンスの動作は同じままです。

4

2 に答える 2

4

なんと興味深い観察でしょう。これをさらに調査するためにできることは次のとおりです。Console.ReadLine のように、プログラムの先頭に「一時停止」を追加しますが、メソッドの最初の呼び出しの後に追加します。次に、「リリース」モードでプログラムをビルドします。次に、デバッガー以外でプログラムを開始します。次に、一時停止で、デバッガーをアタッチします。それをデバッグして、問題のメソッドに対して jit されたコードを見てください。ループ本体を見つけるのはかなり簡単なはずです。

生成されたループ本体が C プログラムのものとどのように異なるかを知ることは興味深いでしょう。

これらすべてのフープがジャンプする理由は、「デバッグ」アセンブリをジッティングするとき、またはデバッガーが既に接続されているプログラムをジッターするときに、ジッターが生成するコードを変更するためです。そのような場合、デバッガーで理解しやすいコードを jit します。この場合に生成された「最良の」コードであるとジッターが判断するものを確認することはより興味深いので、ジッターが実行された後、デバッガーを後でアタッチする必要があります。

于 2010-01-21T15:17:56.627 に答える
3

ボックスのネイティブ コードで同じ操作を実行してみましたか?

ネイティブの 64 ビットの剰余演算が、両方の引数が 32 ビットの範囲内にある特殊な状況であり、基本的にそれを 32 ビット演算に委譲しても驚かないでしょう。(または、おそらくそれを行うのは JIT です...) そのケースを最適化することはかなり理にかなっていますね。

于 2010-01-21T11:26:20.140 に答える