2010-02-03 20 views
12

Tengo curiosidad por saber qué sucede detrás de la escena para convertir un doble en int, por ejemplo int (5666.1)? ¿Va a ser más caro que un static_cast de una clase secundaria para padres? Como la representación de int y double es fundamentalmente diferente, habrá temporales creados durante el proceso y también costosos.Conversión de doble a int detrás de la escena?

Respuesta

18

Cualquier CPU con punto flotante nativo tendrá instrucciones para convertir datos de punto flotante a entero. Esa operación puede tomar desde unos pocos ciclos hasta muchos. Por lo general, hay registros de CPU separados para FP y enteros, por lo que también debe mover el entero a un registro entero antes de poder usarlo. Esa puede ser otra operación, posiblemente costosa. Vea el manual de su procesador.

PowerPC, en particular, no incluye una instrucción para mover un entero en un registro FP a un registro entero. Tiene que haber una tienda de FP a la memoria y de carga a entero. Por lo tanto, puede decir que se crea una variable temporal.

En el caso de que no se admita FP de hardware, el número debe decodificarse. formato IEEE FP es:

sign | exponent + bias | mantissa 

Para convertir, lo que tiene que hacer algo como

// Single-precision format values: 
int const mantissa_bits = 23; // 52 for double. 
int const exponent_bits = 8; // 11 for double. 
int const exponent_bias = 127; // 1023 for double. 

std::int32_t ieee; 
std::memcpy(& ieee, & float_value, sizeof (std::int32_t)); 
std::int32_t mantissa = ieee & (1 << mantissa_bits)-1 | 1 << mantissa_bits; 
int exponent = (ieee >> mantissa_bits & (1 << exponent_bits)-1) 
      - (exponent_bias + mantissa_bits); 
if (exponent <= -32) { 
    mantissa = 0; 
} else if (exponent < 0) { 
    mantissa >>= - exponent; 
} else if (exponent + mantissa_bits + 1 >= 32) { 
    overflow(); 
} else { 
    mantissa <<= exponent; 
} 
if (ieee < 0) mantissa = - mantissa; 
return mantissa; 

es decir, unas cuantas instrucciones de bits desembalaje y un cambio.

4

Existe invariablemente una instrucción FPU dedicada que hace el trabajo, cvttsd2si si el generador de códigos usa el conjunto de instrucciones Intel SSE2. Eso es rápido, pero no tan rápido como un elenco estático. Eso generalmente no requiere ningún código en absoluto.

4

El static_cast depende de la generación de código C++ del compilador, pero generalmente no tiene costo de tiempo de ejecución, ya que el cambio del puntero se calcula en tiempo de compilación en función de la información supuesta en el molde.

Al convertir un doble a int, en un sistema x86 el compilador generará una instrucción FIST (Conversión de punto flotante/entero), y la FPU hará la conversión. Esta conversión se puede implementar en software, y se hace de esta manera en cierto hardware, o si el programa lo requiere. La biblioteca GNU MPFR es capaz de realizar conversiones dobles a int, y realizará la misma conversión en todo el hardware.

+1

Para un x86 moderno, el compilador puede/generará una instrucción SSE2, no un x87. – MSalters

+0

@MSalters: Depende; algunos compiladores "modernos" todavía codifican a la FPU x87 por defecto, pero sí, muchos compiladores emitirán 'cvttsd2si'. –

+0

Sí, en x86-32 no puede suponer que 'cvttsd2si' existe. ¿Pero hay compiladores que usan los ins x87 obsoletos para x86-64? – MSalters