2012-01-26 8 views
7

C++ Visual puede emitir C4738 warning:¿Por qué no hay una advertencia como C4738 para el doble?

almacenar resultado flotador 32 bits en la memoria, la posible pérdida de rendimiento

para los casos cuando un 32-bit float está a punto de ser almacenado en memoria en lugar de siendo almacenado en un registro.

La descripción dice además usando double resuelve el problema. No entiendo por qué esto último es cierto.

¿Por qué el almacenamiento de float en la memoria da como resultado la pérdida de rendimiento y el almacenamiento double no?

Respuesta

7

La advertencia combina dos cuestiones:

  • flotadores deben ser almacenados en la memoria en lugar de registros, lo que puede reducir el rendimiento (porque la memoria es mucho más lento que los registros)
  • flotadores se redondeará (debido a registros tiene 64 u 80 bits siempre, pero en la memoria un flotador solo tiene 32 bits).

El uso de doble resuelve el segundo problema (al menos parcialmente, 64 bits son aún menos precisos que 80 bits), pero no tiene impacto en la posible pérdida de rendimiento. Por lo que la detallada descripción de alerta menciona dos remedios:

Para solucionar esta advertencia y evitar el redondeo, compilar con/fp: rápido o uso de dobles en lugar de flotadores.

Para resolver esta advertencia y evitar quedarse sin registros, cambie el orden de la computación y modificar su uso de inlining

+0

¿Por qué 'float' daría lugar a la pérdida de rendimiento, pero no' double'? – tenfour

+0

@tenfour: * both * dará como resultado la pérdida de rendimiento, pero el doble no se redondeará tanto. –

+2

@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) –

3

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.

Cuestiones relacionadas