亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么將0.1F改為0會使性能降低10倍?

為什么將0.1F改為0會使性能降低10倍?

C++
慕仙森 2019-06-25 11:12:53
為什么將0.1F改為0會使性能降低10倍?為什么這段代碼,const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,                        1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};                        const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,                      1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};float y[16];for (int i = 0; i < 16; i++){     y[i] = x[i];}for (int j = 0; j < 9000000; j++){     for (int i = 0; i < 16; i++)     {         y[i] *= x[i];         y[i] /= z[i];         y[i] = y[i] + 0.1f; // <--         y[i] = y[i] - 0.1f; // <--     }}運行速度超過10倍,比下面的位(相同的,但注意到)?const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,                        1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};                        const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,                      1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};float y[16];for (int i = 0; i < 16; i++){     y[i] = x[i];}for (int j = 0; j < 9000000; j++){     for (int i = 0; i < 16; i++)     {         y[i] *= x[i];         y[i] /= z[i];         y[i] = y[i] + 0; // <--         y[i] = y[i] - 0; // <--     }}使用VisualStudio 2010 SP1編譯時。(我沒有用其他編譯器進行測試。)
查看完整描述

3 回答

?
慕斯709654

TA貢獻1840條經驗 獲得超5個贊

歡迎來到世界非正態浮點!他們會破壞表演!

Denormal(或亞正常)數字是一種從浮點表示中獲得接近于零的額外值的一種方法。對非規范化浮點的操作可以是十到數百倍而不是標準化浮點。這是因為許多處理器無法直接處理它們,必須使用微碼捕獲和解析它們。

如果您在10,000次迭代后打印出數字,您將看到它們已經收斂到不同的值,具體取決于00.1被利用了。

下面是在x64上編譯的測試代碼:

int main() {

    double start = omp_get_wtime();

    const float x[16]={1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0,2.1,2.2,2.3,2.4,2.5,2.6};
    const float z[16]={1.123,1.234,1.345,156.467,1.578,1.689,1.790,1.812,1.923,2.034,2.145,2.256,2.367,2.478,2.589,2.690};
    float y[16];
    for(int i=0;i<16;i++)
    {
        y[i]=x[i];
    }
    for(int j=0;j<9000000;j++)
    {
        for(int i=0;i<16;i++)
        {
            y[i]*=x[i];
            y[i]/=z[i];#ifdef FLOATING
            y[i]=y[i]+0.1f;
            y[i]=y[i]-0.1f;#else
            y[i]=y[i]+0;
            y[i]=y[i]-0;#endif

            if (j > 10000)
                cout << y[i] << "  ";
        }
        if (j > 10000)
            cout << endl;
    }

    double end = omp_get_wtime();
    cout << end - start << endl;

    system("pause");
    return 0;}

產出:

#define FLOATING1.78814e-007  1.3411e-007  1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  
2.16067e-007  1.71363e-007  1.49012e-007  1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-0071.78814e-007  1.3411e-007  
1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  2.16067e-007  1.71363e-007  1.49012e-007 
 1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-007//#define FLOATING6.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044 
  1.54143e-044  2.10195e-044  2.46842e-029  7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044 
   2.66247e-044  2.24208e-0446.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044  1.54143e-044  2.10195e-044  2.45208e-029
     7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044  2.66247e-044  2.24208e-044

注意,在第二次運行中,數字非常接近于零。

非正態化的數字通常很少見,因此大多數處理器無法有效地處理它們。


來證明這與非正態數有關,如果我們平移數為零通過將其添加到代碼的開頭:

_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);

然后版本與0不再慢10倍,實際上變得更快。(這要求在啟用SSE的情況下編譯代碼。)

這意味著,與其使用這些奇怪的、精度較低的幾乎為零的值,我們只是將其舍入為零。

計時:核心i7 [email protected] GHz:

//  Don't flush denormals to zero.0.1f: 0.5640670   : 26.7669//  Flush denormals to zero.0.1f: 0.5871170   : 0.341406

最后,這與它是整數還是浮點無關。這個00.1f被轉換/存儲在兩個循環之外的寄存器中。所以這對性能沒有影響。


查看完整回答
反對 回復 2019-06-25
?
隔江千里

TA貢獻1906條經驗 獲得超10個贊

這是由于非規范化浮點的使用。如何消除它和表現的懲罰?在互聯網上搜索了殺死非正常數字的方法之后,似乎還沒有“最佳”的方法來做到這一點。我發現這三種方法在不同的環境中最有效:

  • 可能在GCC的環境下不起作用:

    // Requires #include <fenv.h>fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV);
  • 可能無法在某些VisualStudio環境中工作:1

    // Requires #include <xmmintrin.h>_mm_setcsr( _mm_getcsr() | (1<<15) | (1<<6) );
    // Does both FTZ and DAZ bits. You can also use just hex value 0x8040 to do both.
    // You might also want to use the underflow mask (1<<11)
  • 在GCC和VisualStudio中都可以使用:

    // Requires #include <xmmintrin.h>// Requires #include <pmmintrin.h>_MM_SET_FLUSH_ZERO_MODE
    (_MM_FLUSH_ZERO_ON);_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  • Intel編譯器可以在現代的Intel CPU上默認禁用非正常值。這里有更多的細節

  • 編譯器開關-ffast-math-msse-mfpmath=sse將禁用取消,并使其他一些事情更快,但不幸的是,也做了許多其他的近似,可能破壞您的代碼。仔細測試!與VisualStudio編譯器的快速數學等價的是/fp:fast但我還沒能證實這是否也是禁用的。1


查看完整回答
反對 回復 2019-06-25
  • 3 回答
  • 0 關注
  • 583 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號