redondear - round c# double
¿El casting doble para flotar siempre devuelve el mismo valor? (6)
¿El casting double
para float
siempre produce el mismo resultado, o puede haber algunas "diferencias de redondeo"?
Por ejemplo, es x
en
float x = (float)0.123456789d;
siempre el mismo valor?
¿Qué pasa cuando se lanza el flotador al doble, y luego se lanza de nuevo para flotar, es decir. (float)(double)someFloat
?
Principalmente interesado en los resultados en C #, pero siéntase libre de compartirlos si tiene conocimiento de cómo funciona esto en otros idiomas.
En algunos casos, la representación float
más cercana a una cantidad numérica puede diferir del valor obtenido al redondear la representación double
más cercana a una float
. Dos de tales cantidades son 12,344,321.4999999991 y 12,345,678.50000000093. Los números enteros por encima y por debajo de ambas cantidades se pueden representar con precisión como float
, pero el double
más cercano a cada una de ellas tiene una parte fraccionaria de 0.5. Debido a que convertir dichos valores double
(entre 2 ^ 23 y 2 ^ 24, con una fracción de exactamente 0,5) para float
se redondeará al entero par más cercano; el compilador terminará redondeando en cada caso el valor que hubiera estado más cerca del número original.
Tenga en cuenta que, en la práctica, el compilador parece analizar los números como double
y luego convertirlos a float
, por lo que aunque 12344321.4999999991f debería redondearse a 12344321f, en su lugar se redondea a 12344322f. Del mismo modo, 12345678.50000000093f debería redondearse a 12345679f pero redondearse a 12345678f, por lo que incluso en los casos en que la conversión a double
y luego float
pierde 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.50000000000f se redondean correctamente.
Los números de punto 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. Entonces, para el ejemplo anterior (0.123456789), los dígitos serían 111010110111100110100010101 (la representación binaria de 123456789). Son 27 dígitos, que caben 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 fuera 0.123456, los dígitos serían 11110001001000000 (17 dígitos) que caben cómodamente en un flotante o un decimal, por lo que no perdería precisión en un lanzamiento de ida y vuelta.
Los resultados no deben depender del idioma, a menos que el idioma se desvíe de la especificación IEEE.
Todas las flotaciones se pueden representar exactamente como dobles, por lo que el viaje de ida y vuelta de flotación a doble a flotación debería producir el mismo valor con el que comenzó.
De manera similar, la conversión de cualquier valor doble para flotar siempre debe producir el mismo resultado, pero, por supuesto, hay muchos valores dobles diferentes que se truncarían en el mismo valor flotante.
Si bajas un double
a un float
, estás perdiendo precisión y datos. La conversión de un float
a un double
es una conversión de ampliación ; no se pierden datos si luego se redondea ... es decir, a menos que haga algo al valor antes de volver a bajar a un flotador.
Los números de punto flotante sacrifican la precisión y la precisión por rango . Los flotadores de precisión simple te dan 32 bits de precisión; La doble precisión te da 64 bits. Pero pueden representar valores fuera de los límites que indicaría la precisión subyacente.
C # float
y double
son valores de punto flotante IEEE 754.
float
es un valor IEEE 754 de precisión simple (32 bits) y consta de un- Signo de 1 bit
- Exponente de 8 bits
- Mantisa de 23 bits / significand
double
es el valor IEEE 754 de doble precisión (64 bits) y consta de un- Signo de 1 bit
- Exponente de 11 bits
- Mantisa de 52 bits / significand
La precisión efectiva de la mantisa es 1 bit más que su tamaño aparente (magia de punto flotante).
Algunos recursos de punto flotante de CLR para usted:
- http://csharpindepth.com/Articles/General/FloatingPoint.aspx
- http://www.extremeoptimization.com/resources/Articles/FPDotNetConceptsAndFormats.aspx
Este documento es probablemente el documento canónico sobre los peligros y las trampas de la aritmética de punto flotante. Si no eres miembro de la ACM, haz clic en el enlace del título para encontrar descargas públicas del artículo:
- David Goldberg. 1991. Lo que todo científico informático debería saber sobre la aritmética de punto flotante . ACM Comput. Surv. 23, 1 (marzo de 1991), 5-48. DOI = 10.1145 / 103162.103163 http://doi.acm.org/10.1145/103162.103163
Resumen
Mucha gente considera que la aritmética de punto flotante es un tema esotérico. Esto es bastante sorprendente, ya que el punto flotante es ubicuo en los sistemas informáticos: casi todos los idiomas tienen un tipo de datos de punto flotante; Las computadoras desde las PC hasta las supercomputadoras tienen aceleradores de punto flotante; la mayoría de los compiladores serán llamados para compilar algoritmos de punto flotante de vez en cuando; y prácticamente todos los sistemas operativos deben responder a excepciones de punto flotante, como el desbordamiento. Este artículo 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 la representación de punto flotante y el error de redondeo, continúa con una discusión del estándar de punto flotante IEEE y concluye con ejemplos de cómo los desarrolladores de sistemas informáticos pueden soportar mejor el punto flotante.
Teniendo en cuenta que tienen una precisión diferente, incluso si está lanzando desde menos precisión a una más amplia (supongo que en realidad es su duda) el resultado no puede ser siempre el mismo.
Las operaciones de punto flotante, especialmente el vaciado, son siempre un tema de truncamiento / redondeo y cualquier otro tipo de aproximación .
Un doble debería ser capaz de mantener exactamente cada valor posible de un flotador. Convertir un flotador en un doble no debe cambiar el valor, y volver a un flotador debe devolver el valor original, siempre y cuando no haya realizado ningún cálculo sobre el doble mientras tanto.