Denormalize kayan nokta dünyasına hoş geldiniz ! Performansa zarar verebilirler !!!
Denormal (veya subnormal) sayılar, kayan nokta gösteriminden sıfıra çok yakın bazı ekstra değerler elde etmek için bir tür hack'tir. Denormalize kayan nokta üzerindeki işlemler, normalleştirilmiş kayan noktadan on kat daha yüzlerce kat daha yavaş olabilir . Bunun nedeni birçok işlemcinin bunları doğrudan işleyememesi ve mikrokod kullanarak bunları yakalayıp çözmesi gerektiğidir.
10.000 tekrardan sonra sayıları yazdırmak varsa, bunların üzerinde olmasına bağlı olarak farklı değerlere yakınsadığıdır göreceksiniz 0
veya 0.1
kullanılır.
İşte x64 üzerinde derlenmiş test kodu:
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;
}
Çıktı:
#define FLOATING
1.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
1.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 FLOATING
6.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-044
6.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
İkinci çalışmada sayıların sıfıra ne kadar yakın olduğuna dikkat edin.
Denormalize sayılar genellikle nadirdir ve bu nedenle çoğu işlemci bunları verimli bir şekilde ele almaya çalışmaz.
Kodun başlangıcına ekleyerek denormalleri sıfıra akıtırsak , bunun denormalize sayılarla ilgisi olduğunu göstermek için:
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
Sonra ile sürüm 0
artık 10 kat daha yavaş değildir ve aslında daha hızlı olur. (Bu, kodun SSE etkinken derlenmesini gerektirir.)
Bu, bu garip düşük hassasiyet neredeyse sıfır değerlerini kullanmak yerine, sadece sıfıra yuvarlıyoruz.
Zamanlamalar: Core i7 920 @ 3,5 GHz:
// Don't flush denormals to zero.
0.1f: 0.564067
0 : 26.7669
// Flush denormals to zero.
0.1f: 0.587117
0 : 0.341406
Sonunda, bunun bir tamsayı veya kayan nokta ile ilgisi yoktur. 0
Ya da 0.1f
her iki döngü bir kayıt dış depolanır / dönüştürülür. Böylece performans üzerinde hiçbir etkisi yoktur.