float entre diferencia decimals c# types floating-point double decimal

c# - entre - ¿Cuándo debo usar el doble en lugar del decimal?



float c# (12)

Puedo nombrar tres ventajas al usar double (o float ) en lugar de decimal :

  1. Utiliza menos memoria.
  2. Más rápido porque las operaciones matemáticas de punto flotante son compatibles de forma nativa con los procesadores.
  3. Puede representar un mayor rango de números.

Pero estas ventajas parecen aplicarse solo a las operaciones de cálculo intensivo, como las que se encuentran en el software de modelado. Por supuesto, los dobles no se deben usar cuando se requiere precisión, como los cálculos financieros. Entonces, ¿existen razones prácticas para elegir el double (o float ) en lugar del decimal en aplicaciones "normales"?

Editado para agregar: Gracias por todas las grandes respuestas, aprendí de ellas.

Una pregunta adicional: algunas personas señalaron que los dobles pueden representar números reales con mayor precisión. Cuando se declara, creo que normalmente también los representan con mayor precisión. ¿Pero es una afirmación verdadera de que la precisión puede disminuir (a veces significativamente) cuando se realizan operaciones de punto flotante?


Depende de para qué lo necesites.

Debido a que flotante y doble son tipos de datos binarios, tiene algunas diferencias y errores en los números de las rondas, por ejemplo, el doble redondearía 0.1 a 0.100000001490116, el doble también redondearía 1/3 a 0.33333334326441. En pocas palabras, no todos los números reales tienen una representación precisa en tipos dobles

Afortunadamente, C # también es compatible con la llamada aritmética de coma flotante decimal, donde los números se representan mediante el sistema numérico decimal en lugar del sistema binario. Por lo tanto, la coma-aritmética de punto flotante decimal no pierde precisión al almacenar y procesar números de punto flotante. Esto hace que sea inmensamente adecuado para cálculos donde se necesita un alto nivel de precisión.


Creo que has resumido las ventajas bastante bien. Sin embargo, te estás perdiendo un punto. El tipo decimal solo es más preciso al representar los números base 10 (por ejemplo, los utilizados en los cálculos de moneda / financieros). En general, el tipo double ofrecerá al menos la mayor precisión (alguien me corrige si me equivoco) y, definitivamente, una mayor velocidad para números reales arbitrarios. La conclusión simple es: cuando considere cuál usar, use siempre el double menos que necesite la precisión base 10 que ofrece el decimal .

Editar:

Con respecto a su pregunta adicional sobre la disminución en la precisión de los números de punto flotante después de las operaciones, este es un problema un poco más sutil. De hecho, la precisión (yo uso el término indistintamente para la precisión aquí) disminuirá constantemente después de que se realice cada operación. Esto se debe a dos razones:

  1. El hecho de que ciertos números (los decimales más obvios) no pueden representarse verdaderamente en forma de punto flotante
  2. Se producen errores de redondeo, como si estuviera haciendo el cálculo a mano. Sin embargo, depende en gran medida del contexto (cuántas operaciones esté realizando) si estos errores son lo suficientemente significativos como para justificar su reflexión.

En todos los casos, si desea comparar dos números de punto flotante que en teoría deberían ser equivalentes (pero se llegó a usar diferentes cálculos), debe permitir un cierto grado de tolerancia (cuánto varía, pero generalmente es muy pequeño) .

Para obtener una descripción más detallada de los casos particulares en los que se pueden introducir errores en las precisiones, consulte la sección Exactitud del artículo de Wikipedia . Finalmente, si desea una discusión seriamente profunda (y matemática) de los números / operaciones de punto flotante a nivel de máquina, intente leer el artículo que se cita a menudo Lo que todo científico informático debería saber sobre la aritmética de punto flotante .


El decimal tiene bytes más anchos, el doble es soportado de forma nativa por la CPU. El decimal es base-10, por lo que se está produciendo una conversión de decimal a doble mientras se calcula un decimal.

For accounting - decimal For finance - double For heavy computation - double

Tenga en cuenta .NET CLR solo admite Math.Pow (doble, doble). Decimal no es compatible.

.NET Framework 4

[SecuritySafeCritical] public static extern double Pow(double x, double y);


Elija el tipo en función de su aplicación. Si necesita precisión como en el análisis financiero, ha respondido a su pregunta. Pero si su aplicación puede resolver con una estimación de su aprobación con doble.

¿Su aplicación necesita un cálculo rápido o tendrá todo el tiempo del mundo para darle una respuesta? Realmente depende del tipo de aplicación.

Gráfico hambriento? flotar o doble es suficiente. ¿Análisis de datos financieros, meteoro golpeando un planeta de precisión? Esos necesitarían un poco de precisión :)


En algunas cuentas, considere la posibilidad de usar tipos integrales en lugar o en conjunto. Por ejemplo, digamos que las reglas bajo las cuales opera requieren que cada resultado de cálculo se lleve a cabo con al menos 6 posiciones decimales y el resultado final se redondeará al centavo más cercano.

Un cálculo de 1/6 de $ 100 produce $ 16.66666666666666 ..., por lo que el valor que se lleva a cabo en una hoja de cálculo será de $ 16.666667. Tanto el doble como el decimal deberían dar ese resultado con precisión a 6 decimales. Sin embargo, podemos evitar cualquier error acumulativo llevando el resultado hacia adelante como un número entero 16666667. Cada cálculo posterior se puede realizar con la misma precisión y se puede realizar de manera similar. Continuando con el ejemplo, calculo el impuesto a las ventas de Texas sobre esa cantidad (16666667 * .0825 = 1375000). Sumando los dos (es una hoja de cálculo corta) 1666667 + 1375000 = 18041667. Mover el punto decimal nuevamente nos da 18.041667, o $ 18.04.

Si bien este breve ejemplo no produciría un error acumulativo al usar doble o decimal, es bastante fácil mostrar casos en los que simplemente calcular el doble o decimal y llevar adelante acumularía un error significativo. Si las reglas bajo las cuales opera requieren un número limitado de lugares decimales, almacene cada valor como un número entero multiplicando por 10 ^ (número requerido de lugar decimal), y luego dividiendo por 10 ^ (número requerido de lugares decimales) para obtener el valor real El valor evitará cualquier error acumulativo.

En situaciones en las que no se producen fracciones de centavos (por ejemplo, una máquina expendedora), no hay ninguna razón para usar tipos que no sean integrales. Simplemente piense en ello como contar centavos, no dólares. He visto un código en el que cada cálculo involucraba solo centavos enteros, ¡pero el uso del doble condujo a errores! Integer solo matemática eliminó el problema. Así que mi respuesta poco convencional es, cuando sea posible, renunciar al doble y al decimal.


Nota: esta publicación se basa en la información de las capacidades del tipo decimal de http://csharpindepth.com/Articles/General/Decimal.aspx y mi propia interpretación de lo que eso significa. Asumiré que Double es la doble precisión IEEE normal.

Nota2: más pequeño y más grande en este post se refiere a la magnitud del número.

Pros de "decimal".

  • "decimal" puede representar números exactos que pueden escribirse como fracciones decimales (suficientemente cortas), el doble no puede. Esto es importante en los libros de contabilidad financiera y es similar, donde es importante que los resultados coincidan exactamente con lo que daría un humano haciendo los cálculos.
  • "decimal" tiene una mantisa mucho más grande que "doble". Eso significa que para los valores dentro de su rango normalizado, "decimal" tendrá una precisión mucho mayor que el doble.

Contras de decimal

  • Será mucho más lento (no tengo puntos de referencia pero supongo que al menos un orden de magnitud quizás más), el decimal no se beneficiará de ninguna aceleración de hardware y la aritmética requerirá una multiplicación / división relativamente cara por potencias de 10 ( que es mucho más costoso que la multiplicación y la división por potencias de 2) para hacer coincidir el exponente antes de la suma / resta y devolver el exponente al rango después de la multiplicación / división.
  • decimal se desbordará antes que doble voluntad. El decimal solo puede representar números de hasta ± 2 96 -1. Por comparación, el doble puede representar números hasta casi ± 2 1024
  • decimal se desbordará antes. Los números más pequeños representables en decimal son ± 10 -28 . Por comparación, el doble puede representar valores hasta 2 -149 (aprox. 10 -45 ) si se admiten números subnromales y 2 -126 (aprox. 10 -38 ) si no lo son.
  • El decimal ocupa el doble de memoria que el doble.

Mi opinión es que debe usar de manera predeterminada el "decimal" para el trabajo con dinero y otros casos en los que el cálculo de la concordancia humana es importante y debe usar el doble como su opción predeterminada durante el resto del tiempo.


Pareces acertado con los beneficios de usar un tipo de punto flotante. Tiendo a diseñar decimales en todos los casos, y confío en un generador de perfiles para avisarme si las operaciones en decimal están causando cuellos de botella o retrasos. En esos casos, "decliné" para doblar o flotar, pero solo lo haré internamente, y trataré de manejar la pérdida de precisión limitando el número de dígitos significativos en la operación matemática que se está realizando.

En general, si su valor es transitorio (no se reutiliza), es seguro usar un tipo de punto flotante. El problema real con los tipos de punto flotante son los siguientes tres escenarios.

  1. Usted está agregando valores de punto flotante (en cuyo caso el compuesto de errores de precisión)
  2. Construye valores basados ​​en el valor de punto flotante (por ejemplo, en un algoritmo recursivo)
  3. Está haciendo matemáticas con un número muy amplio de dígitos significativos (por ejemplo, 123456789.1 * .000000000000000987654321 )

EDITAR

Según la documentación de referencia sobre decimales de C # :

La palabra clave decimal denota un tipo de datos de 128 bits. En comparación con los tipos de punto flotante, el tipo decimal tiene una mayor precisión y un rango más pequeño, lo que lo hace adecuado para cálculos financieros y monetarios.

Así que para aclarar mi declaración anterior:

Tiendo a diseñar decimales en todos los casos, y confío en un generador de perfiles para avisarme si las operaciones en decimal están causando cuellos de botella o retrasos.

Solo he trabajado en industrias donde los decimales son favorables. Si está trabajando en motores físicos o gráficos, es probable que sea mucho más beneficioso diseñar para un tipo de punto flotante (flotante o doble).

El decimal no es infinitamente preciso (es imposible representar una precisión infinita para no integral en un tipo de datos primitivo), pero es mucho más preciso que el doble:

  • decimal = 28-29 dígitos significativos
  • doble = 15-16 dígitos significativos
  • float = 7 dígitos significativos

Editar 2

En respuesta al comentario de Konrad Rudolph , el artículo # 1 (arriba) es definitivamente correcto. La agregación de la imprecisión de hecho se complica. Vea el código de abajo para un ejemplo:

private const float THREE_FIFTHS = 3f / 5f; private const int ONE_MILLION = 1000000; public static void Main(string[] args) { Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10")); float asSingle = 0f; double asDouble = 0d; decimal asDecimal = 0M; for (int i = 0; i < ONE_MILLION; i++) { asSingle += THREE_FIFTHS; asDouble += THREE_FIFTHS; asDecimal += (decimal) THREE_FIFTHS; } Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION); Console.WriteLine("Single: {0}", asSingle.ToString("F10")); Console.WriteLine("Double: {0}", asDouble.ToString("F10")); Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10")); Console.ReadLine(); }

Esto da como resultado lo siguiente:

Three Fifths: 0.6000000000 Six Hundred Thousand: 600000.0000000000 Single: 599093.4000000000 Double: 599999.9999886850 Decimal: 600000.0000000000

Como puede ver, aunque estamos agregando desde la misma constante de origen, los resultados del doble son menos precisos (aunque probablemente se redondearán correctamente), y el flotador es mucho menos preciso, hasta el punto en que se ha reducido a solo Dos dígitos significativos.


Si necesita interrumpir binario con otros lenguajes o plataformas, entonces es posible que necesite usar float o double, que están estandarizados.


Un valor doble se serializará a notación científica de forma predeterminada si esa notación es más corta que la visualización decimal. (por ejemplo, .00000003 será 3e-8) Los valores decimales nunca se serializarán a notación científica. Al serializar para el consumo por un tercero, esto puede ser una consideración.


Use el decimal para los valores de base 10, por ejemplo, cálculos financieros, como otros han sugerido.

Pero el doble es generalmente más preciso para valores calculados arbitrarios.

Por ejemplo, si desea calcular el peso de cada línea en una cartera, use el doble, ya que el resultado se sumará al 100%.

En el siguiente ejemplo, doubleResult está más cerca de 1 que decimalResult:

// Add one third + one third + one third with decimal decimal decimalValue = 1M / 3M; decimal decimalResult = decimalValue + decimalValue + decimalValue; // Add one third + one third + one third with double double doubleValue = 1D / 3D; double doubleResult = doubleValue + doubleValue + doubleValue;

Así que de nuevo tomando el ejemplo de una cartera:

  • El valor de mercado de cada línea de la cartera es un valor monetario y probablemente se represente mejor como decimal.

  • El peso de cada línea en la cartera (= Valor de mercado / SUM (Valor de mercado)) suele representarse mejor como el doble.


Use un doble o un flotador cuando no necesite precisión, por ejemplo, en un juego de plataformas que escribí, usé un flotador para almacenar las velocidades del jugador. Obviamente, no necesito una súper precisión aquí porque eventualmente redondeo a un Int para dibujar en la pantalla.


Utilice puntos flotantes si valora el rendimiento por encima de la corrección.