這也取決於指令組合。你的處理器將有幾個計算單元隨時待命,如果它們全部都被填滿,你將獲得最大的吞吐量。所以,執行一個循環的mul就像執行一個循環或增加一樣快 - 但是如果表達式變得更復雜,這個循環不成立。
例如,藉此循環:
for(int j=0;j<NUMITER;j++) {
for(int i=1;i<NUMEL;i++) {
bla += 2.1 + arr1[i] + arr2[i] + arr3[i] + arr4[i] ;
}
}
爲NUMITER = 10^7,NUMEL = 10^2,初始化爲小的正數(NaN的是慢得多)兩個陣列,這需要使用6.0秒雙64位處理器。如果我有
bla += 2.1 * arr1[i] + arr2[i] + arr3[i] * arr4[i] ;
更換循環只需要1.7秒......所以,因爲我們「過火」的補充,該MULS基本上免費的;減少添加物有所幫助。它得到的更加混亂:
bla += 2.1 + arr1[i] * arr2[i] + arr3[i] * arr4[i] ;
- 同MUL /加分配,但現在不斷的在增加,而不是相乘 - 需要3.7秒。您的處理器可能被優化爲更有效地執行典型的數值計算;所以像摩爾和縮比和的總和就像它的總和一樣好。加常數並不常見,因此速度較慢...
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; /*someval == 2.1*/
再次需要1.7秒。
bla += someval + arr1[i] + arr2[i] + arr3[i] + arr4[i] ; /*someval == 2.1*/
(與初始循環相同,但沒有昂貴的常數加法:2。1秒)
bla += someval * arr1[i] * arr2[i] * arr3[i] * arr4[i] ; /*someval == 2.1*/
(大多MULS,但是一個另外1.9秒爲單位)
所以,基本上;很難說哪個更快,但是如果你想避免瓶頸,更重要的是要有一個健全的組合,避免NaN或INF,避免添加常量。不管你做什麼,都要確保你測試並測試各種編譯器設置,因爲通常很小的更改只能改變它們。
一些更多的情況:
bla *= someval; // someval very near 1.0; takes 2.1 seconds
bla *= arr1[i] ;// arr1[i] all very near 1.0; takes 66(!) seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; // 1.6 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, 2.2 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, floats 2.2 seconds
bla += someval * arr1[i]* arr2[i];// 0.9 in x64, 1.6 in x86
bla += someval * arr1[i];// 0.55 in x64, 0.8 in x86
bla += arr1[i] * arr2[i];// 0.8 in x64, 0.8 in x86, 0.95 in CLR+x64, 0.8 in CLR+x86
非常酷的文件。我認爲有一點仍然是一致的(而且這份文件顯示了這一點),那就是分裂的速度遠遠大於乘法,加法和減法。從本文看來,雙精度除法的延遲比乘法慢10倍。所以,例如,我相信調用x = y * 0.5應該比調用x = y/2更快。 – 2009-07-20 15:20:16
@SteveWortham您能否指向頁面,您發現有關fdiv的信息比fmul慢10倍? – 0fnt 2012-05-11 06:05:12