2012-03-16 15 views
20

¿La fundición double a float produce siempre el mismo resultado, o puede haber algunas "diferencias de redondeo"?¿El doble de fundición flota siempre el mismo valor?

Por ejemplo, es x en

float x = (float)0.123456789d; 

siempre el mismo valor?

¿Qué sucede cuando el fundido flota al doble, y luego lo echa hacia atrás para flotar, es decir. (float)(double)someFloat?

Principalmente interesado en saber cuáles son los resultados en C#, pero siéntete libre de compartirlo si tienes conocimiento de cómo funciona esto en otros idiomas.

+0

@Moozhe No en C#, donde el sufijo decimal es "m". – phoog

+0

@Moozhe Incorrecto, 'd' _is_ for double. 'M' es para decimal (y es abreviatura de" dinero "). http://msdn.microsoft.com/en-us/library/bfft1t3c.aspx –

+0

Vaya, lo siento. Estaba equivocado. –

Respuesta

13

Los resultados no deben depender del idioma, a menos que el lenguaje se desvíe de la especificación IEEE.

Todos los flotadores se pueden representar exactamente como dobles, por lo que el viaje de ida y vuelta desde el flotador al doble para flotar debería producir el mismo valor con el que comenzó.

Del mismo modo, emitir cualquier valor doble para flotar siempre debe dar el mismo resultado, pero, por supuesto, hay muchos valores dobles diferentes que se truncarían al mismo valor flotante.

1

Una doble debe ser capaz de mantener exactamente todos los valores posibles de un flotador. Lanzar un float a un double no debería cambiar el valor, y devolverlo a un float debería devolver el valor original, siempre y cuando no hayas realizado ningún cálculo en el double mientras tanto.

1

Teniendo en cuenta que tienen una precisión diferente, incluso si estás lanzando desde menos precisión a uno más ancho (supongo que esa es realmente tu duda) el resultado no puede ser siempre lo mismo.

Las operaciones de punto flotante, especialmente la fundición, son siempre un tema de truncado/redondeo y cualquier otro tipo de aproximación .

+3

Esto no es del todo cierto. Las operaciones de punto flotante binario dan como resultado aproximaciones cuando intenta usarlas para representar números decimales. La aproximación se produce debido a la conversión de una base a otra. Float y double son ambos tipos de datos base-2, por lo que el tipo de datos más grande puede representar exactamente cualquier valor que pueda tener el tipo más pequeño. – phoog

+0

@phoog: realmente no entiendo su punto: '(double) 4.123401f' es igual en standart' ToString() '==' 4.12340116500854'. ** No es el mismo número **. Utilice o no use, el número que está en la celda de doble no es lo mismo. – Tigran

+0

@phoog: mal. La representación binaria es ** no ** lo mismo también. – Tigran

0

Los números de coma flotante en C# se almacenan utilizando el formato IEEE 754 (http://en.wikipedia.org/wiki/IEEE_754). Este formato tiene dos partes: los dígitos y el exponente. Los dobles tienen 52 dígitos, y los flotadores tienen 23 dígitos. La base es 2, no diez. Por lo tanto, para su ejemplo anterior (0.123456789), los dígitos serían 111010110111100110100010101 (la representación binaria de 123456789). Eso es 27 dígitos, que se ajusta cómodamente en un doble, pero no en un flotador, así que sí, la precisión se perdería en la conversión de ida y vuelta.

Por otro lado, si su número era 0.123456, los dígitos serían 11110001001000000 (17 dígitos) que se ajustan cómodamente en un flotador o un decimal, por lo que no perdería precisión en un lanzamiento de ida y vuelta.

+0

La representación binaria de '0.123456789d' es en realidad' 0011111110111111100110101101110100110111001110010110001101011111'; la mantisa es '(1) .1111100110101101110100110111001110010110001101011111'. El valor flotante correspondiente es '00111101111111001101011011101010' (mantissa' (1) .11111001101011011101010'). Ninguno de los dos valores se adapta cómodamente al tamaño de un doble, y mucho menos un flotador, beccause '123456789/1000000000' se repite infinitamente en la base 2. – phoog

0

Compilado con gcc en mac. . . .

#include <stdio.h> 
int main() 
{ 
    double x = 0.123456789; 
    float y = x; 
    double z = y; 

    printf ("x=%9.9f\n",x); 
    printf ("y=%9.9f\n",y); 
    printf ("z=%9.9f\n",z); 
} 

Escupe esto. . .

./a.out 
x=0.123456789 
y=0.123456791 
z=0.123456791 
+0

Nadie discute que convertir un doble en un flotador puede cambiar el valor. La pregunta es si ir en la dirección opuesta puede cambiar el valor. en otras palabras, su programa debería leer 'float x = something; doble y = x; flotar z = (float) y; '. Ah, y la pregunta era preguntar acerca de C#. – phoog

6

Si abatido un double a un float, que está perdiendo precisión y datos. Upcasting un float a un double es un ampliación conversión; no se pierde ningún dato si se dispara por la mitad ...es decir, a menos que haga algo al valor anterior a la bajada a un valor flotante.

Los números de coma flotante sacrifican precisión y precisión para rango. Los flotadores de precisión simple te dan 32 bits de precisión; la precisión doble te da 64 bits. Pero pueden representar valores muy por fuera de los límites que indicaría la precisión subyacente.

C# float y double son valores de punto flotante IEEE 754.

La precisión efectiva de la mantisa es de 1 bit más de su tamaño aparente (magia de punto flotante).

Algunos recursos CLR coma flotante para usted:

Este papel es probablemente el papel canónico sobre los peligros y las trampas de la aritmética de coma flotante. Si no es miembro de la ACM, haga clic en el enlace del título para buscar descargas públicas del artículo:

  • David Goldberg. 1991. What every computer scientist should know about floating-point arithmetic. ACM Comput. Surv. 23, 1 (marzo de 1991), 5-48. DOI = 10,1145/103162,103163 http://doi.acm.org/10.1145/103162.103163

    Resumen
    aritmética de punto flotante se considera como sujeto esotérica por muchas personas. Esto es bastante sorprendente, porque el punto flotante es omnipresente en los sistemas informáticos: Casi todos los idiomas tienen un tipo de datos de coma flotante; computadoras desde PC a supercomputadoras tienen aceleradores de punto flotante; la mayoría de los compiladores serán llamados al para compilar algoritmos de coma flotante de vez en cuando; y prácticamente todos los sistemas operativos deben responder a excepciones de coma flotante como el desbordamiento. Este documento presenta un tutorial sobre los aspectos de punto flotante que tienen un impacto directo en los diseñadores de sistemas informáticos.Comienza con el fondo en representación flotante y error de redondeo, continúa con una discusión del estándar de punto flotante IEEE , y concluye con ejemplos de cómo los constructores de sistemas informáticos pueden admitir mejor punto flotante.

1

En algunos casos, la float representación más cercana a una cantidad numérica puede diferir del valor obtenido mediante el redondeo del double representación más cercana a un float. Dos de esas cantidades son 12,344,321.4999999991 y 12,345,678.50000000093. Los números enteros superiores e inferiores a ambas cantidades se representan con precisión como float, pero el double más cercano a cada uno de ellos tiene una parte fraccionaria de 0,5 con precisión. Debido a que la conversión de dichos valores double (entre 2^23 y 2^24, con una fracción de precisión de 0.5) a float redondeará al entero par más cercano; el compilador en cada caso terminará redondeando lejos del valor que habría estado más cerca del número original.

Tenga en cuenta que, en la práctica, el compilador parece analizar números double, y luego convertir a float, así que aunque 12344321.4999999991f debe redondear a 12344321f, en su lugar se redondea a 12344322f. Del mismo modo 12345678.50000000093f debe redondear a 12345679f pero redondea a 12345678f, por lo que incluso en los casos en que la conversión a double y luego a float pierda precisión, dicha pérdida de conversión no se puede evitar especificando números directamente como float.

Por cierto, los valores 12344321.4999999992f y 12345678.50000000094f se redondean correctamente.

Cuestiones relacionadas