c# - name - ¿Es un doble realmente inadecuado para el dinero?
remarks c# (8)
Dado que el decimal
usa un factor de escala de múltiplos de 10, los números como 0.1 se pueden representar exactamente. En esencia, el tipo decimal representa esto como 1/10 ^ 1, mientras que un double
representaría esto como 104857/2 ^ 20 (en realidad sería más como realmente-gran-número / 2 ^ 1023).
Un decimal
puede representar exactamente cualquier valor de base 10 con hasta 28/29 dígitos significativos (como 0.1). Un double
no puede.
Siempre digo en c # una variable de tipo doble no es adecuada para dinero. Todas las cosas raras podrían suceder. Pero parece que no puedo crear un ejemplo para demostrar algunos de estos problemas. ¿Alguien puede dar ese ejemplo?
(editar; esta publicación se etiquetó originalmente C #; algunas respuestas se refieren a detalles específicos de decimal
, que por lo tanto significa System.Decimal
).
(Edición 2: Yo era específico pidiendo un código c #, así que no creo que esto sea independiente del idioma)
En realidad, el doble punto flotante es perfectamente adecuado para representar cantidades de dinero siempre que elija una unidad adecuada.
Ver http://www.idinews.com/moneyRep.html
Lo mismo ocurre con el punto fijo de largo . O bien consume 8 bytes, seguramente preferible a los 16 consumidos por un elemento decimal .
Si algo funciona o no (es decir, produce el resultado esperado y correcto) no es una cuestión de voto o preferencia individual. Una técnica funciona o no funciona.
Muy, muy inadecuado. Usa decimal
double x = 3.65, y = 0.05, z = 3.7;
Console.WriteLine((x + y) == z); // false
(ejemplo de la página de Jon here - lectura recomendada ;-p)
Ningún doble siempre tendrá errores de redondeo, use "decimal" si está en .Net ...
Obtendrá errores ocasionales causados por el redondeo. Además, las comparaciones con los valores exactos son extremadamente complicadas: por lo general, debe aplicar algún tipo de épsilon para verificar que el valor real esté "cerca" de uno en particular.
Aquí hay un ejemplo concreto:
using System;
class Test
{
static void Main()
{
double x = 0.1;
double y = x + x + x;
Console.WriteLine(y == 0.3); // Prints False
}
}
Sí, no es adecuado.
Si mal no recuerdo, el doble tiene alrededor de 17 números significativos, por lo que normalmente los errores de redondeo se producirán muy por detrás del punto decimal. La mayoría del software financiero usa 4 decimales detrás del punto decimal, lo que deja 13 decimales para trabajar, por lo que el número máximo con el que puede trabajar para operaciones individuales es aún mucho mayor que la deuda nacional de EE. UU. Pero los errores de redondeo se sumarán con el tiempo. Si su software se ejecuta durante un tiempo prolongado, eventualmente comenzará a perder centavos. Ciertas operaciones empeorarán esto. Por ejemplo, agregar grandes cantidades a pequeñas cantidades causará una pérdida significativa de precisión.
Necesita tipos de datos de punto fijo para operaciones de dinero, a la mayoría de las personas no les importa si pierde un centavo aquí y allá, pero los contadores no son como la mayoría de las personas.
editar
De acuerdo con este sitio http://msdn.microsoft.com/en-us/library/678hzkk9.aspx realidad, los doblados tienen de 15 a 16 dígitos significativos en lugar de 17.
@Jon Skeet decimal es más adecuado que el doble debido a su mayor precisión, 28 o 29 decimales significativos. Eso significa menos posibilidades de que los errores de redondeo acumulados se vuelvan significativos. Los tipos de datos de puntos fijos (es decir, enteros que representan centavos o centésimas de centavo como he visto) como las menciones de Boojum son en realidad los más adecuados.
Según entiendo, la mayoría de los sistemas financieros expresan moneda utilizando números enteros, es decir, contando todo en centavos.
La precisión doble IEEE en realidad puede representar todos los enteros exactamente en el rango -2 ^ 53 a + 2 ^ 53. (Hacker''s Delight, página 262) Si solo usa suma, resta y multiplicación, y mantiene todo en números enteros dentro de este rango, entonces no debería perder precisión. Sin embargo, sería muy cauteloso con la división o las operaciones más complejas.
Usar doble cuando no sabes lo que estás haciendo no es adecuado.
"doble" puede representar una cantidad de un billón de dólares con un error de 1/90 de un centavo. Entonces obtendrás resultados altamente precisos. ¿Quieres calcular cuánto cuesta poner a un hombre en Marte y recuperarlo vivo? doble hará bien.
Pero con el dinero a menudo hay reglas muy específicas que dicen que un determinado cálculo debe dar un resultado determinado y ningún otro. Si calcula una cantidad muy muy muy próxima a $ 98.135, a menudo existirá una regla que determinará si el resultado debe ser $ 98.14 o $ 98.13 y debe seguir esa regla y obtener el resultado que se requiere.
Dependiendo de dónde viva, usar enteros de 64 bits para representar centavos o centavos o kopeks o lo que sea que sea la unidad más pequeña en su país generalmente funcionará bien. Por ejemplo, los enteros con signo de 64 bits que representan centavos pueden representar valores de hasta 92,223 billones de dólares. Los enteros de 32 bits generalmente no son adecuados.