2010-01-11 17 views
17

¿Los bits subyacentes simplemente se "reinterpretan" como un valor de coma flotante? ¿O hay una conversión en tiempo de ejecución para producir el valor del punto flotante más cercano?¿Qué sucede en C++ cuando un tipo entero se convierte en un tipo de coma flotante o viceversa?

¿Es la endianidad un factor en cualquier plataforma (es decir, endianness of floats difiere de ints)?

¿Cómo se comportan los diferentes tipos de ancho (por ejemplo, int para flotar vs. int para el doble)?

¿Qué garantiza el estándar de idioma sobre la seguridad de dichos moldes/conversiones? Por elenco, me refiero a un elenco de static_cast o C-style.

¿Qué ocurre con la conversión inversa de float a int (o de doble a int)? Si un flotante tiene un valor de magnitud pequeño (p. Ej., 2), ¿el patrón de bits tiene el mismo significado cuando se interpreta como un int?

+2

Lea * §4.9 - Conversiones integrales flotantes *. –

+0

Acepto que esta pregunta debe ser respondida por investigación propia: D tendríamos que copiar las normas de pegado y los manuales de la CPU: D –

+0

@StringRay: http://stackoverflow.com/questions/81656/where-do-i-find-the -corrent-c-or-c-standard-documents –

Respuesta

10

Haz los bits subyacentes acaba de obtener "reinterpretado" como un valor de punto flotante?

No, el valor se convierte de acuerdo con las reglas de la norma.

hay una conversión de tiempo de ejecución para producir el valor de punto flotante más cercano?

Sí hay una conversión en tiempo de ejecución.

Para coma flotante -> entero, el valor se trunca, siempre que el valor fuente esté dentro del rango del tipo entero. Si no es así, el comportamiento no está definido. Al menos creo que es el valor de la fuente, no el resultado, lo que importa. Tendría que buscarlo para estar seguro. El caso límite si el tipo de destino es char, por ejemplo, sería CHAR_MAX + 0.5. Creo que no está definido lanzarlo a char, pero como digo no estoy seguro.

Para número entero -> punto flotante, el resultado es el mismo valor exacto si es posible, o de lo contrario es uno de los dos valores de coma flotante a cada lado del valor entero. No necesariamente el más cercano de los dos.

¿Es endianness un factor en cualquier plataforma (es decir, endianness de floats difiere de ints)?

No, nunca. Las conversiones se definen en términos de valores, no de representaciones de almacenamiento.

¿Cómo se comportan los diferentes tipos de ancho (por ejemplo, int para flotar vs. int para el doble)?

Todo lo que importa son los rangos y las precisiones de los tipos.Suponiendo 32 bit ints y IEEE 32 bit floats, es posible que una conversión int-> float sea impreciso. Suponiendo también dobles IEEE de 64 bits, no es posible que una conversión int-> doble sea imprecisa, porque todos los valores int se pueden representar exactamente como un doble.

¿Qué garantiza el estándar de idioma sobre la seguridad de dichos moldes/conversiones? Por elenco, me refiero a un elenco de static_cast o C-style.

Como se indicó anteriormente, es seguro excepto en el caso en que un valor de coma flotante se convierta en un tipo entero, y el valor esté fuera del rango del tipo de destino.

Si un flotador tiene un valor de magnitud pequeño (por ejemplo, 2), ¿el patrón de bits tiene el mismo significado cuando se interpreta como un int?

No, no es así. La representación IEEE de 32 bits de 2 es 0x40000000.

2

Al convertir un número entero en un flotante, no es probable que pierda ninguna precisión a menos que se trate de enteros extremadamente grandes.

Cuando convierte un flotador en un int, básicamente está realizando la operación floor(). por lo que sólo gotas de los bits después del decimal

Para obtener más información acerca de coma flotante lee: http://www.lahey.com/float.htm

El formato IEEE de precisión simple tiene 24 bits de mantisa, 8 bits de exponente, y un bit de signo. Los registros internos de coma flotante en microprocesadores Intel como el Pentium tienen 64 bits de mantisa, 15 bits de exponente y un bit de signo. Esto permite que los cálculos intermedios se realicen con mucha menos pérdida de precisión que muchas otras implementaciones. La desventaja de esto es que, dependiendo de cómo se guardan los valores intermedios en los registros, los cálculos que parecen iguales pueden dar resultados diferentes.

Si su número entero usa más de 24 bits (excluyendo el bit de guía oculto), entonces es probable que pierda algo de precisión en la conversión.

+0

Creo que su primera frase fue pensada para ser "... un entero para una carroza ..." –

+0

Gracias, lo arreglé. – zmbush

+0

@Stingray: Sí, un truncamiento: "La conversión trunca; es decir, la parte fraccionaria se descarta". –

5

Para referencia, esto es lo ISO-IEC 14882 hasta 2003 dice

4.9 flotantes-Integral conversiones

Un valor p de un tipo de coma flotante pueden ser convertidos a un valor p de un entero tipo. La conversión trunca; es decir, la parte fraccional se descarta. El comportamiento no está definido si el valor truncado no se puede representar en el tipo de destino. [Nota: si el tipo de destino es `bool, vea 4.12. ]

Un valor r de un tipo entero o de un tipo de enumeración se puede convertir a un valor r de un tipo de coma flotante. El resultado es exacto si es posible. De lo contrario, es una elección definida por la implementación del próximo valor representable más bajo o más alto. [Nota: la pérdida de precisión ocurre si el valor integral no se puede representar exactamente como un valor del tipo flotante. ] Si el tipo de fuente es bool, el valor false se convierte en cero y el valor true se convierte en uno.

Referencia: What Every Computer Scientist Should Know About Floating-Point Arithmetic

Otros altamente valiosos referencias sobre el tema de la rápida float a int conversiones:

¡Que tenga una buena lectura!

+0

sí, implica un impacto en el rendimiento, estoy editando la pregunta con más referencias de interés –

+0

consulte los manuales de Intel, por ejemplo, para las instrucciones de ensamblaje en coma flotante. Para encontrarlo más fácilmente, cree una pequeña aplicación de demostración en C++ y ábrala en un desensamblador. Luego busca las instrucciones. Allí encontrarás toda la información que necesitas (al menos para intel cpus). –

2

¿Reinterpreted? El término "reinterpretación" generalmente se refiere a la reinterpretación de la memoria en bruto. Por supuesto, es imposible reinterpretar significativamente un valor entero como un valor de punto flotante (y viceversa) ya que sus representaciones físicas son generalmente completamente diferentes.

Cuando lanzas los tipos, un tiempo de ejecución de conversión se está realizando (en contraposición a reinterpretación). La conversión normalmente no es solo conceptual, sino que requiere un esfuerzo real en tiempo de ejecución, debido a la diferencia en la representación física. No hay relaciones definidas en el lenguaje entre los patrones de bits de los valores de origen y destino. La endianidad tampoco juega ningún papel en ella.

Al convertir un valor entero a un tipo de punto flotante, el valor original se convierte exactamente si se puede representar exactamente por el tipo de destino. De lo contrario, el valor será cambiado por el proceso de conversión.

Al convertir un valor de punto flotante a tipo entero, la parte fraccional simplemente se descarta (es decir, no se toma el valor más cercano, pero el número se redondea hacia cero). Si el resultado no encaja en el tipo de entero de destino, el comportamiento no está definido.

Tenga en cuenta también que las conversiones de punto flotante a entero (y viceversa) son conversiones estándar y no requieren formalmente ningún tipo de conversión explícita. A veces, las personas pueden usar un molde explícito para suprimir las advertencias del compilador.

4

Normalmente hay conversiones en tiempo de ejecución, ya que las representaciones de bits generalmente no son compatibles (con la excepción de que el 0 binario normalmente es 0 y 0.0). Los estándares C y C++ solo tratan con el valor, no con la representación, y especifican un comportamiento generalmente razonable. Recuerde que un valor int grande normalmente no será exactamente representable en un float, y un valor grande float no puede ser representado por un int.

Por lo tanto:

Todas las conversiones son por valor, no patrones de bits. No te preocupes por los patrones de bits.

No se preocupe por la endianidad, ya que es una cuestión de representación bit a bit.

La conversión de int a puede perder precisión si el valor entero es grande en valor absoluto; es menos probable que con double, ya que double es más preciso y puede representar muchos más números exactos. (Los detalles dependen de qué representaciones esté usando el sistema en realidad).)

Las definiciones de idioma no dicen nada acerca de los patrones de bits.

La conversión de float a también es una cuestión de valores, no de patrones de bits. Un punto flotante 2.0 exacto se convertirá en una integral 2 porque así es como se configura la implementación, no debido a los patrones de bits.

+0

+1 por "comportamiento generalmente razonable". Lo único que normalmente debe recordar es que float to int truncates en lugar de redondear (a diferencia de .NET); de lo contrario, es sencillo. (Los problemas de precisión perdida se pueden ignorar si se aplica a "doble" y "largo" ...) – AAT

0

Si echas el valor en sí, se convertirá (por lo que en un flotante -> int conversión 3.14 se convierte en 3).

Pero si lanza el puntero, entonces realmente 'reinterpretará' los bits subyacentes. Por lo tanto, si hace algo como esto:

double d = 3.14; 
int x = *reinterpret_cast<int *>(&d); 

x tendrá un valor 'aleatorio' que se basa en la representación del punto flotante.

0

La conversión de FP a tipo integral no es trivial y no está completamente definida.

Normalmente el FPU ejecuta una instrucción de hardware para convertir de formato IEEE a int. Esa instrucción podría tomar parámetros (implementados en hardware) que controlen el redondeo. Es probable que su ABI especifique de igual a igual. Si tiene X86 + SSE, es "probablemente no demasiado lento", pero no puedo encontrar una referencia con una búsqueda en Google.

Como con cualquier cosa FP, hay casos de esquina. Sería bueno si el infinito estuviera mapeado en (TYPE)_MAX, pero por desgracia no es el caso, el resultado de int x = INFINITY; no está definido.

Cuestiones relacionadas