2013-01-04 28 views
3

可能重複:
Are doubles faster than floats in c#?簡單的數學運算在double上比在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); 
    } 

我得到了這樣的結果(版本,沒有調試,英特爾移動酷睿雙核T2500 2.0GHz的CPU 2MB):

Preparing data 5275,6862ms 

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

我很驚訝,上double操作幾乎比float上的操作快3倍。我搜索了「雙浮」在這裏,我發現這一點:

Is using double faster than float?

最好的答案是專注於CPU架構,但我不能同意這一點。

我懷疑別的東西會導致浮點運算性能低下,因爲我的英特爾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 
+0

請注意,使用浮點數進行任何長時間的數值計算都會很快導致累積舍入誤差的風險。 –

+1

與'NextDouble'小麥相比,你'NextFloat'的分佈非常不同。我不知道這是否有任何關聯。但請注意,'NextDouble'在'0.0'和'1.0'之間創建一個數字,它是1.0/2147483647.0的整數倍。所以這個數字的「結尾」並不是真正的隨機數,當計算產品或商數時,這可能很重要。 –

+0

@JeppeStigNielsen重要;看到我的答案。改變它們使得它們都生成0到1之間的數字從根本上改變了我在修改之前和之後運行OP代碼的運行時間。 – Servy

回答

6

它與您如何生成隨機數有關。乘積和劃分浮點數並不完全相同;這些數字的實際值很重要。在浮動的情況下,你正在一個相當大的範圍內填充一個值。如果您創建的浮標數量在0到1之間,就像雙打一樣,那麼它就會像您期望的那樣出現。只要改變NextFloat是這樣的:

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

我只是跑了一些測試,並與改變花車分別爲33%快了乘法。

當然,這只是使比較「公平」的最簡單方法。爲了更好地理解浮點數如何與雙精度浮點數進行比較,您希望在各個類型的整個範圍之間生成隨機浮點數和雙精度浮點數,或者更好,這兩個浮點數都表示程序將使用的數據類型。

+1

這是正確的。如果你做這個改變,浮體性能比雙性能稍微好一些。 – Pete

+0

漂亮!固定後的時間:倍數浮動:107,5963ms 倍增倍數:132,2323ms 分隔浮線:160,1531ms 分隔雙打:170,8343ms。現在對我來說是有道理的。 – Kamil

+0

也許這會更公平地說:'static float NextFloat(Random random){return random.Next(32767)/ 32767f; }原因是'NextDouble'不使用'double'的完整精度。它只產生數值是'1.0/2147483647.0'倍數的數字,精度約爲十位十進制數字,而'double'的精度約爲十六位十進制數字。 –

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。您可以嘗試Mono,它提供JIT編譯爲SIMD指令的內在方法。或者,您可以使用本機代碼來實現對性能敏感的部分,因爲現代C++編譯器不僅可以使用SIMD,還可以將普通代碼自動向量化爲SIMD指令。