Aunque no estoy 100% seguro de la causa, esto es mi conjetura.
Al compilar en x86 y SSE2 no está activado, el compilador debe utilizar la pila x87 FP para todos los registros de coma flotante. En MSVC, el modo FP, por defecto, establece el redondeo de precisión de 53 bits. (Creo. No estoy 100% seguro de esto.)
Por lo tanto, todas las operaciones realizadas en el FP-pila es en doble precisión.
Sin embargo, cuando algo es arrojado a un float
, la precisión tiene que ser redondeado a la precisión simple. La única forma de hacerlo es almacenarlo en la memoria a través de la instrucción fstp
en un operando de memoria de 4 bytes, y volver a cargarlo.
Veamos el ejemplo de la C4738 warning page se enlazó a:
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);
}
Cuando se llama a func()
, d
es probablemente almacena en un registro x87. Sin embargo, la llamada a func()
requiere que la precisión se reduzca a precisión simple. Esto causará que el d
se redondee/almacene en la memoria. Luego se recargó y re-promovió a doble precisión en la línea f = f1 + f2;
.
Sin embargo, si utiliza double
durante todo el proceso, el compilador puede mantener d
en el registro, omitiendo así la sobrecarga de ir y volver a la memoria.
En cuanto a por qué podría hacerte quedar sin registros ... No tengo ni idea. Es posible que la semántica del programa resulte en tener valores de doble precisión y de precisión simple del mismo valor, que, en este caso, requieren un registro adicional.
¿Por qué 'float' daría lugar a la pérdida de rendimiento, pero no' double'? – tenfour
@tenfour: * both * dará como resultado la pérdida de rendimiento, pero el doble no se redondeará tanto. –
@tenfour: Cuando oculta un registro de punto flotante de 64 bits en una ubicación de memoria de 32 bits, debe redondear, y el redondeo lleva tiempo. Cuando esconde un registro de punto flotante de 64 bits en una ubicación de memoria de 64 bits, no necesita redondear, simplemente almacenar. (La mayoría de los puntos flotantes ya no funcionan con los registros SSE, por lo que el material de 80 bits es, por lo general, irrelevante) –