¿Cuándo debo usar doble en lugar de decimal?


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

  1. Usa menos memoria.
  2. Más rápido porque las operaciones matemáticas de coma flotante son soportadas de forma nativa por los procesadores.
  3. Puede representar un rango mayor de números.

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

Editado para añadir: Gracias por todas las grandes respuestas, aprendí de ellos.

Una pregunta más: Algunas personas señalaron que los dobles pueden representar números reales con mayor precisión. Cuando se declara, yo pensaría que por lo general también los representan con mayor precisión. Pero, ¿es una afirmación verdadera que la precisión puede disminuir (a veces significativamente) al flotar ¿se realizan operaciones puntuales?

Author: HerbalMart, 2009-04-29

12 answers

Creo que has resumido las ventajas bastante bien. Sin embargo, le falta un punto. Las decimal type solo es más preciso al representar números de base 10 (por ejemplo, los utilizados en cálculos monetarios/financieros). En general, el double tipo va a ofrecer al menos como gran precisión (alguien me corrija si me equivoco) y definitivamente mayor velocidad para números reales arbitrarios. La simple conclusión es: al considerar cuál usar, siempre use double a menos que necesita la precisión base 10 que decimal ofrece.

Editar:

Con respecto a su pregunta adicional sobre la disminución en la precisión de los números de coma flotante después de las operaciones, este es un problema ligeramente más sutil. De hecho, la precisión (utilizo 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 (la mayoría obviamente decimales) no pueden ser realmente representados en forma de coma 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 mucho pensamiento.

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

Para una descripción más detallada de los casos particulares en los que se pueden introducir errores en las precisiones, consulte la sección de Precisión del artículo de Wikipedia. Finalmente, si desea una discusión seria en profundidad (y matemática) de los números/operaciones de coma flotante a nivel de máquina, intente leer el artículo frecuentemente citado Lo Que Todo Científico De La Computación Debe Saber Sobre La Aritmética De Coma Flotante.

 288
Author: Noldorin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-20 12:39:12

Parece perfecto con los beneficios de usar un tipo de coma flotante. Tiendo a diseñar para decimales en todos los casos, y confío en un generador de perfiles que me avise si las operaciones con decimales están causando cuellos de botella o ralentizaciones. En esos casos," lanzaré " hacia abajo para doblar o flotar, pero solo lo haré internamente, y trataré cuidadosamente 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 reutilizado), es seguro usar un tipo de punto flotante. El verdadero problema con los tipos de coma flotante son los siguientes tres escenarios.

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

EDITAR

De acuerdo con la documentación de referencia sobre decimales de C# :

La palabra clave decimal denota a tipo de datos de 128 bits. En comparación con tipos de coma flotante, el tipo decimal tiene una mayor precisión y una menor rango, lo que lo hace adecuado para cálculos financieros y monetarios.

Así que para aclarar mi declaración anterior:

Tiendo a diseñar para decimales en todos casos, y confiar en un perfilador para dejar me saber si las operaciones en decimal es causar cuellos de botella o ralentizaciones.

Solo he trabajado en industrias donde los decimales son favorables. Si estás trabajando en phsyics o motores gráficos, probablemente sea mucho más beneficioso diseñar para un tipo de punto flotante (float o double).

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

  • decimal = 28-29 significativo dígitos
  • 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 imprecisiones de hecho se agrava. Vea el siguiente código para ver 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 produce lo siguiente:

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

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

 54
Author: Michael Meadows,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:33:17

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

Pero double es generalmente más preciso para valores calculados arbitrariamente.

Por ejemplo, si desea calcular el peso de cada línea en una cartera, use double ya que el resultado casi sumará hasta el 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:

  • Las el valor de mercado de cada línea en la cartera es un valor monetario y probablemente se representaría mejor como decimal.

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

 22
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-29 20:12:25

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 súper precisión aquí porque eventualmente redondeo a un Int para dibujar en la pantalla.

 6
Author: FlySwat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-29 16:42:46

En algunas Cuentas, considere la posibilidad de usar tipos integrales en su lugar o en conjunción. Por ejemplo, digamos que las reglas bajo las que opera requieren que cada resultado de cálculo se arrastre con al menos 6 decimales y el resultado final se redondeará al centavo más cercano.

Un cálculo de 1/6 de $100 rinde 1 16.6666666666666666..., por lo que el valor llevado a cabo en una hoja de trabajo será de $16.666667. Tanto el doble como el decimal deben producir ese resultado con precisión a 6 decimales. Sin embargo, podemos evitar cualquier error acumulativo llevando el resultado hacia adelante como un entero 16666667. Cada cálculo posterior puede hacerse con la misma precisión y llevarse a cabo de manera similar. Continuando con el ejemplo, calculo el impuesto de ventas de Texas sobre esa cantidad (16666667 * .0825 = 1375000). Agregar los dos (es una hoja de trabajo corta) 1666667 + 1375000 = 18041667. Mover el punto decimal hacia atrás nos da 18.041667, o $18.04.

Mientras que este breve ejemplo no produciría un error acumulativo usando 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 que opera requieren un número limitado de lugares decimales, almacenar cada valor como un entero multiplicando por 10^(#requerido de lugar decimal) y luego dividiendo por 10^(#requerido de lugares decimales) para obtener el valor real evitará cualquier error acumulativo.

En situaciones donde fracciones de los centavos no ocurren (por ejemplo, una máquina expendedora), no hay razón para usar tipos no integrales en absoluto. Simplemente piense en ello como contar centavos, no dólares. He visto código donde cada cálculo implicaba solo centavos enteros, sin embargo, el uso de doble llevó a errores! Entero solo matemáticas eliminó el problema. Así que mi respuesta poco convencional es, cuando sea posible, renunciar al doble y al decimal.

 4
Author: G DeMasters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-30 23:26:40

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

 3
Author: Will Dean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-29 16:47:34

Nota: este post 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 doble es doble precisión normal.

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

Pros de "decimal".

  • "decimal" puede representar exactamente números que se pueden escribir como fracciones decimales (suficientemente cortas) , el doble no puede. Esto es importante en los libros contables financieros y similares, donde es importante que los resultados coincidan exactamente con lo que daría un ser humano haciendo los cálculos.
  • "decimal" tiene una mantisa mucho mayor 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 tal vez más), el decimal no se beneficiará de ninguna aceleración de hardware y la aritmética en él requerirá multiplicación/división relativamente costosa por potencias de 10 (que es mucho más caro que la multiplicación y el dividión por potencias de 2) para coincidir con el exponente antes de la suma/resta y para traer el exponente de nuevo en el rango después de la multiplicación/división.
  • el decimal se desbordará antes que el doble. decimal solo puede representar números hasta ±296-1 . Por comparación el doble puede representar números hasta casi ±21024
  • el decimal se desbordará antes. Los números más pequeños representables en decimal son ±10-28 . Por comparación doble puede representar valores de a 2-149 (aprox 10-45) si subnromal se admiten números 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 por defecto "decimal" para el trabajo de dinero y otros casos en los que el cálculo humano coincidente exactamente es importante y que debe utilizar use double como su opción predeterminada el resto del tiempo.

 2
Author: plugwash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-22 16:33:15

Utilice puntos flotantes si valora el rendimiento sobre la corrección.

 0
Author: Mark Brackett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-29 16:56:59

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 solicitud puede llegar a un acuerdo con una estimación de su ok con el doble.

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

¿Hambriento de gráficos? flotar o doble es suficiente. Análisis de datos financieros, meteorito golpeando un planeta tipo de la precisión ? Esos necesitarían un poco de precisión:)

 0
Author: Khan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-29 17:16:30

Decimal tiene bytes más anchos, double es soportado nativamente por CPU. El decimal es base-10, por lo que se realiza 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 que.NET CLR solo admite matemáticas.Pow (doble, doble). Decimal no es compatible.

. NET Framework 4

[SecuritySafeCritical]
public static extern double Pow(double x, double y);
 0
Author: Jeson Martajaya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-17 21:38:30

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

 0
Author: chris klassen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-17 21:55:09

Depende de para qué lo necesites.

Debido a que float y double son tipos de datos binarios, tiene algunos diifculties and errrors in the way in rounds numbers, so for instance double would round 0.1 to 0.100000001490116, double would also round 1 / 3 to 0.33333334326441. En pocas palabras, no todos los números reales tienen una representación precisa en tipos dobles

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

 0
Author: Neil Meyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-07 12:34:52