3

重複の可能性:
double は c# の float よりも高速ですか?

doubleアプリケーションでデータ型を変更してどの程度のパフォーマンスが得られるかを確認するための簡単なベンチマークを作成しfloatました。これが私のコードです:

    // my form: 
    // one textbox: textbox1 (MultiLine property set to true)
    // one button: button1 with event button1_Click

    private void button1_Click(object sender, EventArgs e)
    {

        int num = 10000000;

        float[] floats1 = new float[num];
        float[] floats2 = new float[num];
        float[] floatsr = new float[num];  // array for results
        double[] doubles1 = new double[num];
        double[] doubles2 = new double[num];
        double[] doublesr = new double[num]; // array for results

        Stopwatch stw = new Stopwatch();

        log("Preparing data");

        Random rnd = new Random();

        stw.Start();

        for (int i = 0; i < num; i++)
        {
            floats1[i] = NextFloat(rnd);
            floats2[i] = NextFloat(rnd);
            doubles1[i] = rnd.NextDouble();
            doubles2[i] = rnd.NextDouble();
        }
        stw.Stop();
        log(stw.Elapsed.TotalMilliseconds.ToString()+"ms");
        stw.Reset();




        log("");


        stw.Start();
        for (int i = 0; i <# i++)
        {
            floatsr[i] = floats1[i] * floats2[i];
        }
        stw.Stop();
        log("Multiplying floats: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();



        stw.Start();
        for (int i = 0; i < num; i++)
        {
            doublesr[i] = doubles1[i] * doubles2[i];
        }
        stw.Stop();
        log("Multiplying doubles: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();


        stw.Start();
        for (int i = 0; i < num; i++)
        {
            floatsr[i] = floats1[i] / floats2[i];
        }
        stw.Stop();
        log("Dividing floats: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();


        stw.Start();
        for (int i = 0; i < num; i++)
        {
            doublesr[i] = doubles1[i] / doubles2[i];
        }
        stw.Stop();
        log("Dividing doubles: " + stw.Elapsed.TotalMilliseconds.ToString() + "ms");
        stw.Reset();

    }

    private void log(string text)
    {
        textBox1.Text = textBox1.Text + text + Environment.NewLine;
    }

    // I found that function somewhere on stackoverflow
    static float NextFloat(Random random)
    {
        double mantissa = (random.NextDouble() * 2.0) - 1.0;
        double exponent = Math.Pow(2.0, random.Next(-126, 128));
        return (float)(mantissa * exponent);
    }

次のような結果が得られました (リリース、デバッグなし、Intel Mobile Core Duo T2500 2.0GHz 2MB CPU):

Preparing data 5275,6862ms

Multiplying floats: 442,7865ms 
Multiplying doubles: 169,4028ms
Dividing floats: 550,7052ms 
Dividing doubles: 164,1607ms

doubleでの操作は での操作よりもほぼ 3 倍高速であることに驚きましたfloat。ここで「ダブルフロート」を検索したところ、これが見つかりました:

float より double の方が速いですか?

最良の答えはCPUアーキテクチャに焦点を当てていますが、私はそれに同意できません。

Intel SSE を搭載した私の CPU は、一度に 4 つの浮動小数点数 (パックされた浮動小数点命令) を乗算または除算するか、一度に 2 つの倍精度浮動小数点数を乗算または除算できるはずなので、他の何かが浮動小数点数のパフォーマンスを低下させていると思われます。したがって、フロートはより高速になるはずです。

コンパイラ(または.netのclr)が何らかの方法でメモリ使用量を最適化しているのでしょうか?

最適化してフロートを高速化する方法はありますか?

重複を報告しないでください。他の質問を見ましたが、満足できませんでした。


フロートを生成する方法を変更した後の私の結果は、うまく見えるようになりました(Servyによって提案されました):

Preparing data 1367,0678ms

Multiplying floats: 109,8742ms 
Multiplying doubles: 149,9555ms
Dividing floats: 167,0079ms 
Dividing doubles: 168,6821ms
4

2 に答える 2

6

これは、乱数の生成方法に関係しています。浮動小数点数の乗算と除算はすべて同じではありません。これらの数値の実際の値が重要です。フロートの場合、かなり広い範囲で値を入力しています。double のように 0 と 1 の間になるように float を作成すると、期待どおりの結果が得られます。これに変更NextFloatするだけです:

static float NextFloat(Random random)
{
    return (float) random.NextDouble();
}

いくつかのテストを実行したところ、その変更により、浮動小数点数の乗算が 33% 高速になりました。

もちろん、これは比較を「公正」にするための最も簡単な方法です。float が double と実際にどのように比較されるかをよりよく理解するには、それぞれの型の全範囲の間でランダムな float と double をそれぞれ生成するか、プログラムが使用するデータの型を表す値を両方とも保持することをお勧めします。

于 2013-01-04T14:36:42.943 に答える
4

フロートでのGPU操作は、32ビットのフロートハードウェアを備えているため、場合によってははるかに高速です。

x86(またはx86_64)アーキテクチャCPUは、数学コプロセッサで32ビットをサポートしていません。または64ビットサポートですら。x87浮動小数点ユニットは80ビット演算を使用します。

現在、最新のx86 CPUには、32ビットおよび64ビットの浮動小数点演算をハードウェアでサポートするSIMD命令(MMX、SSE、AVX)があり、SIMDユニットですべてを実行できる場合は、はるかに高いパフォーマンスが得られます。SIMDとFPUの間でデータを移動すると、パフォーマンスが低下します。

また、現在のバージョンでは、.NETはMMX、SSE、またはAVXを使用していません。SIMD命令にJITコンパイルする固有のメソッドを提供するMonoを試してみてください。または、パフォーマンスに最も敏感な部分にネイティブコードを使用することもできます。これは、最新のC ++コンパイラがSIMDの使用を許可するだけでなく、通常の外観のコードをSIMD命令に自動ベクトル化できるためです。

于 2013-01-04T14:35:29.863 に答える