Chociaż nie jestem w 100% pewien przyczyny, oto moje przypuszczenie.
Podczas kompilacji na x86 i SSE2 nie jest włączona, kompilator musi używać stosu XP x87 dla wszystkich rejestrów zmiennoprzecinkowych. W MSVC domyślnie tryb FP jest ustawiony na 53-bitowe zaokrąglenie precyzyjne. (Myślę, że nie jestem w 100% pewny).
Dlatego wszystkie operacje wykonywane na stosie FP są wykonywane z podwójną precyzją.
Jednak, gdy coś jest rzucane do float
, precyzja musi być zaokrąglona do pojedynczej precyzji. Jedynym sposobem, aby to zrobić, jest zapisanie go w pamięci za pomocą instrukcji fstp
przez 4-bajtowy operand pamięci - i ponowne załadowanie.
Spójrzmy na przykład na C4738 warning page ty związane z:
float func(float f)
{
return f;
}
int main()
{
extern float f, f1, f2;
double d = 0.0;
f1 = func(d);
f2 = (float) d;
f = f1 + f2; // C4738
printf_s("%f\n", f);
}
Po wywołaniu func()
, d
jest prawdopodobnie przechowywane w rejestrze x87. Jednak połączenie z numerem func()
wymaga obniżenia precyzji do pojedynczej precyzji. To spowoduje, że d
zostanie zaokrąglone/zapisane w pamięci. Następnie ponownie załadowano i ponownie promowano do podwójnej precyzji linii f = f1 + f2;
.
Jednakże, jeśli używasz double
przez cały czas, kompilator może przechowywać d
w rejestrze - tym samym pomijając napływ do i z pamięci.
Co do tego, dlaczego może zabraknąć rejestrów ... Nie mam pojęcia. Możliwe, że semantyka programu może spowodować uzyskanie zarówno podwójnej precyzji, jak i wartości o pojedynczej precyzji, o tej samej wartości - co w tym przypadku wymaga dodatkowego rejestru.
Dlaczego "unoszenie się" powodowałoby utratę wydajności, ale nie "podwójne"? – tenfour
@tenfour: * oba * spowodują utratę wydajności, ale podwójna wartość nie zostanie zaokrąglona tak bardzo. –
@tenfour: Gdy przechowujesz 64-bitowy rejestr zmiennoprzecinkowy w 32-bitowej pamięci, musisz zaokrąglić, a zaokrąglanie zajmuje trochę czasu. Kiedy przechowujesz 64-bitowy rejestr zmiennoprzecinkowy w 64-bitowej pamięci, nie musisz zaokrąglać, po prostu przechowywać. (Większość liczb zmiennoprzecinkowych jest teraz nieczynna z rejestrami SSE, więc rzeczy 80-bitowe są nieistotne.) –