2009-04-29 10 views
228

puedo nombrar tres ventajas de utilizar double (o float) en lugar de decimal:¿Cuándo debería usar el doble en lugar del decimal?

  1. usa 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 una mayor gama 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 deben usarse cuando se requiere precisión, como los cálculos financieros. Entonces, ¿hay alguna razón práctica para elegir alguna vez double (o float) en lugar de decimal en aplicaciones "normales"?

Editado para agregar: Gracias por todas las excelentes respuestas, aprendí de ellos.

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

+0

ver también http://stackoverflow.com/questions/2545567/in-net-how-do-i-choose-between-a-decimal-and-a-double –

+3

Esto se actualiza bastante regularmente y todavía me cuesta con eso. Por ejemplo, estoy trabajando en una aplicación que hace cálculos financieros, así que estoy usando decimales en todas partes. Pero las funciones Math y VisualBasic.Financial usan el doble, por lo que hay una gran cantidad de conversiones que me hacen dudar constantemente sobre el uso del decimal. –

+0

@JamieIde que está loco. Las funciones financieras usan el doble, el dinero siempre debe estar en decimales. –

Respuesta

273

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

Editar:

cuanto a su pregunta sobre la disminución de la exactitud de los números de punto flotante después de operaciones, este es un tema un poco más sutil. De hecho, la precisión (uso aquí el término de manera intercambiable para la precisión) disminuirá constantemente después de cada operación. Esto se debe a dos razones: a) el hecho de que ciertos números (más obviamente decimales) no pueden representarse realmente en forma de coma flotante, b) ocurren errores de redondeo, como si estuvieras haciendo el cálculo a mano. Depende en gran medida del contexto (cuántas operaciones está realizando) si estos errores son lo suficientemente significativos como para justificarlo.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 ellos utilizando 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 de precisión, consulte la sección Precisión de Wikipedia article. Finalmente, si desea una discusión 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 What Every Computer Scientist Should Know About Floating-Point Arithmetic.

+1

¿Puede proporcionar un ejemplo de un número de base 10 con el que se pierde precisión al convertir a la base 2? –

+0

@Mark: 1.000001 es un ejemplo, al menos según Jon Skeet. (Consulte la pregunta 3 de esta página: http://www.yoda.arachsys.com/csharp/teasers-answers.html) – Noldorin

+18

@Mark: ejemplo muy simple: 0.1 es una fracción periódica en la base 2 por lo que no se puede expresar con precisión en un 'doble'. Las computadoras modernas seguirán imprimiendo el valor correcto, pero solo porque "adivinan" el resultado, no porque realmente se exprese correctamente. –

6

Usa un doble o un flotador cuando no necesitas precisión, por ejemplo, en un juego de plataformas que escribí, utilicé un flotador para almacenar las velocidades del jugador. Obviamente no necesito superprecisión aquí porque eventualmente redondeo a un Int para dibujar en la pantalla.

+3

La precisión es la ÚNICA ventaja de los decimales, esto es correcto. No debería estar preguntando cuándo debería usar números de coma flotante sobre decimales. Ese debería ser tu primer pensamiento. La pregunta es cuándo deberías usar decimales (y la respuesta está aquí ... cuando la precisión importa). –

+2

@Daniel Straight, es gracioso, pero tengo la opinión contraria. Creo que usar un tipo menos preciso debido a sus características de rendimiento equivale a una preoptimización. Posiblemente tendrá que pagar esa preoptimización muchas veces antes de darse cuenta de su beneficio. –

+3

@Michael Meadows, puedo entender este argumento. Sin embargo, algo a tener en cuenta es que una de las principales quejas con una optimización prematura es que los programadores no suelen saber qué va a ser lento. Sin embargo, sabemos sin ninguna duda que los decimales son más lentos que los dobles. Sin embargo, supongo que en la mayoría de los casos, la mejora del rendimiento no será notable para el usuario de todos modos. Por supuesto, en la mayoría de los casos, la precisión tampoco es necesaria. Je. –

50

Parece que tiene las ventajas de utilizar un tipo de punto flotante. Tiendo a diseñar decimales en todos los casos, y confío en un generador de perfiles para saber si las operaciones en decimal están causando cuellos de botella o ralentizaciones. En esos casos, voy a "lanzar hacia abajo" para doblar o flotar, pero solo lo hago internamente, y trato de manejar la pérdida de precisión al limitar 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), puede usar un tipo de coma flotante. El problema real con los tipos de coma flotante son los siguientes tres escenarios.

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

EDITAR

A egún el reference documentation on C# decimals:

El decimal palabra denota un tipo de datos de 128 bits. Comparado con 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 para los decimales en todos casos, y confiar en un generador de perfiles para dejar quisiera saber si las operaciones en decimal es cuellos de botella que causan o lenta -descendientes.

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

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:

  • decimales = 28-29 dígitos significativos
  • dobles = 15-16 dígitos significativos
  • flotador = 7 dígitos significativos

EDIT 2

En respuesta al comentario de Konrad Rudolph, el elemento 1 (arriba) es definitivamente correcto. La agregación de la imprecisión sí es compuesta. Ver el código de abajo 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 da el siguiente resultado:

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

Como se puede ver, a pesar de que estamos añadiendo a la misma fuente constante y los resultados de la doble es menos preciso (aunque probablemente se redondee correctamente), y el flotador es mucho menos preciso, hasta el punto en que se ha reducido a solo dos dígitos significativos.

+1

El punto 1 es incorrecto. Los errores de precisión/redondeo solo ocurren en el lanzamiento, no en los cálculos. * Es * por supuesto correcto que la mayoría de las operaciones matemáticas son inestables, lo que multiplica el error. Pero este es otro problema y se aplica de la misma manera para todos los tipos de datos de precisión limitada, por lo que en particular para los decimales. –

+1

@Konrad Rudolph, vea el ejemplo en "EDIT 2" como evidencia del punto que estaba tratando de hacer en el ítem n. ° 1. A menudo, este problema no se manifiesta porque la imprecisión positiva se balancea con la imprecisión negativa, y se lavan en conjunto, pero agregando el mismo número (como lo hice en el ejemplo) resalta el problema. –

+0

Gran ejemplo. Acabo de mostrarlo a mis desarrolladores junior, los niños se sorprendieron. – Machado

3

Si necesita intercalar binarios con otros lenguajes o plataformas, entonces puede necesitar usar float o double, que están estandarizados.

0

Use los puntos flotantes si valora el rendimiento en lugar de la corrección.

+6

Los números decimales no son más correctos, excepto en ciertos casos limitados que a veces (de ninguna manera siempre) son importantes. –

0

Elija el tipo en función de su aplicación. Si necesita precisión, como en el análisis financiero, ha respondido su pregunta. Pero si su solicitud puede llegar a un acuerdo, haga una estimación de que está bien con el 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.

Graphic hambriento? flotador o doble es suficiente. Análisis de datos financieros, ¿el meteorito golpea un tipo de precisión planetaria? Esos necesitarían un poco de precisión :)

+8

Los números decimales también son estimaciones. Se ajustan a las convenciones de la aritmética financiera, pero no hay ninguna ventaja en, por ejemplo, los cálculos que involucran la física. –

21

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

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

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

En el siguiente ejemplo, doubleResult está más cerca de 1 de 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 en la cartera es un valor monetario y probablemente estaría mejor representado como decimal.

  • El peso de cada línea en la cartera (= Valor de mercado/SUMA (Valor de mercado)) generalmente se representa mejor como el doble.

+1

+1 ¡Ejemplo simple y fácil! –

-1

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

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

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

.NET Framework 4

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

A valores dobles serializará a la notación científica por defecto si que la notación es más corta que la pantalla decimal. (Por ejemplo, .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.

4

En algunos aspectos contables, considere la posibilidad de utilizar tipos integrales en su lugar o en conjunto. Por ejemplo, supongamos que las reglas bajo las que opera requieren que cada resultado de cálculo se mantenga al menos con 6 decimales y el resultado final se redondeará al centavo más cercano.

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

Si bien este breve ejemplo no arrojaría un error acumulativo con doble o decimal, es bastante fácil mostrar casos en los que simplemente calcular el doble o decimal y el almacenamiento acumularía un error significativo. Si las reglas con las que opera requieren un número limitado de decimales, almacenar cada valor como un número entero multiplicando por 10^(número de lugar decimal requerido), y luego dividir entre 10^(número de lugares decimales requeridos) para obtener el valor real el valor evitará cualquier error acumulado.

En situaciones donde no se producen fracciones de centavos (por ejemplo, una máquina expendedora), no hay ninguna razón para usar tipos no integrales en absoluto. Simplemente piense en ello como contando centavos, no dólares. He visto código en el que cada cálculo involucraba solo centavos enteros, ¡pero el uso del doble condujo a errores! Entero solo en matemáticas eliminó el problema. Entonces, mi respuesta no convencional es, cuando es posible, renunciar tanto al doble como a la decimal.

2

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

Nota 2: la más pequeña y la más grande en esta publicación se refieren a la magnitud del número.

Pros de "decimal".

  • "decimal" puede representar exactamente los 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 un humano haría con los cálculos.
  • "decimal" tiene una mantisa mucho más grande que "doble". Eso significa que para valores dentro de su rango normalizado "decimal" tendrá una precisión mucho mayor que el doble.

contras de decimal

  • será mucho más lenta (no tengo puntos de referencia, pero yo supongo al menos un orden de magnitud tal vez más), decimal no se beneficiará de ninguna aceleración de hardware y la aritmética requerirá multiplicación/división relativamente costosa por potencias de 10 (que es mucho más costosa que la multiplicación y división por potencias de 2) para hacer coincidir el exponente antes de la suma/resta y para volver a poner el exponente en el rango después de la multiplicación/división.
  • decimal se desbordará antes de que doble voluntad. decimal solo puede representar números hasta & plusmn; 2 -1.Por comparación, el doble puede representar números hasta casi & plusmn; 2
  • decimal subdesbordará antes. Los números más pequeños representables en decimal son & plusmn; 10 -28. Por comparación doble puede representar valores hasta 2 -149 (aprox 10 -45) si los números subnromal son compatibles y 2 -126 (aprox 10 -38) si no lo son.
  • decimal ocupa el doble de memoria que el doble.

Mi opinión es que debe usar de forma predeterminada "decimal" para el dinero y otros casos en los que coincida exactamente el cálculo humano es importante y debe usar el doble como opción predeterminada el resto del tiempo.

0

Depende de lo que necesite.

Debido float y double son tipos de datos binarios que tiene algunos diifculties y Errrors en la forma en números redondos, por lo que, por ejemplo, el doble que redondear 0,1-0,100000001490116, doble haría también la ronda 1/3 0,33333334326441. Simplemente 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 aritmética de coma flotante decimal no pierde exactitud 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.

Cuestiones relacionadas