Mentre io non sono sicuro al 100% della causa, ecco la mia ipotesi.
Quando la compilazione su x86 e SSE2 non è abilitata, il compilatore deve utilizzare lo stack FP x87 per tutti i registri a virgola mobile. Su MSVC, la modalità FP, per impostazione predefinita, imposta l'arrotondamento di precisione a 53 bit. (Penso che non ne sia sicuro al 100%.)
Pertanto, tutte le operazioni eseguite sullo stack FP sono a precisione doppia.
Tuttavia, quando qualcosa viene ridotto a uno float
, la precisione deve essere arrotondata a precisione singola. L'unico modo per farlo è archiviarlo in memoria tramite l'istruzione fstp
su un operando di memoria a 4 byte e ricaricarlo.
Guardiamo l'esempio sul C4738 warning page si è collegato al:
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);
}
Quando si chiama func()
, d
è probabilmente memorizzato in un registro x87. Tuttavia, la chiamata a func()
richiede che la precisione venga ridotta a precisione singola. Questo farà sì che d
venga arrotondato/archiviato in memoria. Quindi ricaricato e ri-promosso a doppia precisione sulla linea f = f1 + f2;
.
Tuttavia, se si utilizza double
per tutto il percorso, il compilatore può mantenere d
nel registro, evitando così il sovraccarico di andare ae dalla memoria.
Per quanto riguarda il motivo per cui potrebbe farti esaurire i registri ... Non ne ho idea. È possibile che la semantica del programma risulti avere valori di precisione doppia e precisione singola dello stesso valore, che in questo caso richiedono un registro aggiuntivo.
Perché il risultato 'float' comporta una perdita di prestazioni, ma non' double'? – tenfour
@tenfour: * entrambi * provocheranno una perdita di prestazioni, ma il doppio non verrà arrotondato. –
@tenfour: quando si memorizza un registro a virgola mobile a 64 bit in una posizione di memoria a 32 bit, è necessario arrotondare e l'arrotondamento richiede tempo. Quando si memorizza un registro a virgola mobile a 64 bit in una posizione di memoria a 64 bit, non è necessario eseguire il round, è sufficiente memorizzare. (La maggior parte dei punti flottanti ora è inattiva con i registri SSE, quindi la roba a 80 bit è _usualmente_ irrilevante.) –