ventajas tipo sucia mixto flotacion flexible fijo ejemplos desventajas caracteristicas cambio floating-point currency

floating point - tipo - ¿Por qué no usar doble o flotar para representar la moneda?



tipo de cambio flotacion sucia (14)

Como se dijo anteriormente, "representar el dinero como un doble o flotante probablemente se verá bien al principio, ya que el software redondea los pequeños errores, pero a medida que realiza más adiciones, restas, multiplicaciones y divisiones en números inexactos, perderá más y más precisión. a medida que se acumulan los errores. Esto hace que las flotaciones y los dobles sean inadecuados para tratar con el dinero, donde se requiere una precisión perfecta para múltiplos de potencias de base 10 ".

¡Finalmente Java tiene una forma estándar de trabajar con Currency And Money!

JSR 354: API de dinero y moneda

JSR 354 proporciona una API para representar, transportar y realizar cálculos completos con dinero y moneda. Puedes descargarlo desde este enlace:

JSR 354: Descarga del API de Money and Currency

La especificación consta de las siguientes cosas:

  1. Una API para el manejo, por ejemplo, montos monetarios y monedas.
  2. APIs para soportar implementaciones intercambiables
  3. Fábricas para crear instancias de las clases de implementación.
  4. Funcionalidad para cálculos, conversión y formateo de importes monetarios.
  5. API de Java para trabajar con Money y Currencies, que se planea incluir en Java 9.
  6. Todas las clases de especificación e interfaces se encuentran en el paquete javax.money. *.

Ejemplos de ejemplo de JSR 354: API de Money and Currency:

Un ejemplo de cómo crear un Monto Monetario e imprimirlo en la consola tiene este aspecto:

MonetaryAmountFactory<?> amountFactory = Monetary.getDefaultAmountFactory(); MonetaryAmount monetaryAmount = amountFactory.setCurrency(Monetary.getCurrency("EUR")).setNumber(12345.67).create(); MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault()); System.out.println(format.format(monetaryAmount));

Cuando se utiliza la API de implementación de referencia, el código necesario es mucho más simple:

MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR"); MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault()); System.out.println(format.format(monetaryAmount));

La API también admite cálculos con montos monetarios:

MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR"); MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));

MonedaUnidad y Monto Monetario

// getting CurrencyUnits by locale CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN); CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);

MonetaryAmount tiene varios métodos que permiten acceder a la moneda asignada, el monto numérico, su precisión y más:

MonetaryAmount monetaryAmount = Money.of(123.45, euro); CurrencyUnit currency = monetaryAmount.getCurrency(); NumberValue numberValue = monetaryAmount.getNumber(); int intValue = numberValue.intValue(); // 123 double doubleValue = numberValue.doubleValue(); // 123.45 long fractionDenominator = numberValue.getAmountFractionDenominator(); // 100 long fractionNumerator = numberValue.getAmountFractionNumerator(); // 45 int precision = numberValue.getPrecision(); // 5 // NumberValue extends java.lang.Number. // So we assign numberValue to a variable of type Number Number number = numberValue;

Los montos monetarios se pueden redondear utilizando un operador de redondeo:

CurrencyUnit usd = MonetaryCurrencies.getCurrency("USD"); MonetaryAmount dollars = Money.of(12.34567, usd); MonetaryOperator roundingOperator = MonetaryRoundings.getRounding(usd); MonetaryAmount roundedDollars = dollars.with(roundingOperator); // USD 12.35

Cuando se trabaja con colecciones de Montos Monetarios, hay disponibles algunos métodos útiles de utilidad para filtrar, clasificar y agrupar.

List<MonetaryAmount> amounts = new ArrayList<>(); amounts.add(Money.of(2, "EUR")); amounts.add(Money.of(42, "USD")); amounts.add(Money.of(7, "USD")); amounts.add(Money.of(13.37, "JPY")); amounts.add(Money.of(18, "USD"));

Operaciones monetarias personalizadas

// A monetary operator that returns 10% of the input MonetaryAmount // Implemented using Java 8 Lambdas MonetaryOperator tenPercentOperator = (MonetaryAmount amount) -> { BigDecimal baseAmount = amount.getNumber().numberValue(BigDecimal.class); BigDecimal tenPercent = baseAmount.multiply(new BigDecimal("0.1")); return Money.of(tenPercent, amount.getCurrency()); }; MonetaryAmount dollars = Money.of(12.34567, "USD"); // apply tenPercentOperator to MonetaryAmount MonetaryAmount tenPercentDollars = dollars.with(tenPercentOperator); // USD 1.234567

Recursos:

Manejo de dinero y monedas en Java con JSR 354

Buscando en la API de Java 9 Money y Currency (JSR 354)

Ver también: JSR 354 - Moneda y dinero

Siempre me han dicho que nunca represente dinero con tipos double o float , y esta vez le pregunto: ¿por qué?

Estoy seguro de que hay una muy buena razón, simplemente no sé cuál es.


El resultado del número de punto flotante no es exacto, lo que los hace inadecuados para cualquier cálculo financiero que requiera un resultado exacto y no una aproximación. float y double están diseñados para el cálculo científico y de ingeniería, y muchas veces no producen resultados exactos, ya que el cálculo del punto flotante puede variar de JVM a JVM. Mire el ejemplo de BigDecimal y la primitiva doble que se usa para representar el valor monetario, es bastante claro que el cálculo de punto flotante puede no ser exacto y se debe usar BigDecimal para los cálculos financieros.

// floating point calculation final double amount1 = 2.0; final double amount2 = 1.1; System.out.println("difference between 2.0 and 1.1 using double is: " + (amount1 - amount2)); // Use BigDecimal for financial calculation final BigDecimal amount3 = new BigDecimal("2.0"); final BigDecimal amount4 = new BigDecimal("1.1"); System.out.println("difference between 2.0 and 1.1 using BigDecimal is: " + (amount3.subtract(amount4)));

Salida:

difference between 2.0 and 1.1 using double is: 0.8999999999999999 difference between 2.0 and 1.1 using BigDecimal is: 0.9


Esto no es una cuestión de precisión, ni es una cuestión de precisión. Es una cuestión de satisfacer las expectativas de los humanos que usan la base 10 para los cálculos en lugar de la base 2. Por ejemplo, el uso de dobles para los cálculos financieros no produce respuestas que son "incorrectas" en un sentido matemático, pero puede producir respuestas que son No es lo que se espera en un sentido financiero.

Incluso si redondea sus resultados en el último minuto antes de la salida, de vez en cuando puede obtener un resultado utilizando dobles que no cumplan con las expectativas.

Usando una calculadora, o calculando resultados a mano, 1.40 * 165 = 231 exactamente. Sin embargo, utilizando internamente dobles, en mi entorno de compilador / sistema operativo, se almacena como un número binario cercano a 230.99999 ... así que si trunca el número, obtendrá 230 en lugar de 231. Puede razonar que el redondeo en lugar de truncar han dado el resultado deseado de 231. Eso es cierto, pero el redondeo siempre implica un truncamiento. Independientemente de la técnica de redondeo que utilice, todavía hay condiciones de contorno como esta que se redondearán cuando espere que se redondeen. Son lo suficientemente raros que a menudo no se encontrarán a través de pruebas u observaciones ocasionales. Es posible que deba escribir algún código para buscar ejemplos que ilustren los resultados que no se comportan como se espera.

Supongamos que desea redondear algo al centavo más cercano. Así que tomas tu resultado final, multiplícalo por 100, sumas 0.5, truncas, luego divides el resultado por 100 para volver a los centavos. Si el número interno que almacenó era 3.46499999 ... en lugar de 3.465, obtendrá 3.46 en lugar de 3.47 cuando redondee el número al centavo más cercano. Pero sus cálculos de base 10 pueden haber indicado que la respuesta debe ser 3.465 exactamente, lo que claramente debería redondear a 3.47, no a 3.46. Este tipo de cosas ocurren ocasionalmente en la vida real cuando se usan dobles para cálculos financieros. Es raro, por lo que a menudo pasa desapercibido como un problema, pero sucede.

Si usa la base 10 para sus cálculos internos en lugar de dobles, las respuestas son siempre exactamente lo que esperan los humanos, asumiendo que no haya otros errores en su código.


Estoy preocupado por algunas de estas respuestas. Creo que los dobles y los flotadores tienen un lugar en los cálculos financieros. Ciertamente, al sumar y restar montos monetarios no fraccionarios no habrá pérdida de precisión al usar clases de enteros o clases de BigDecimal. Pero al realizar operaciones más complejas, a menudo terminas con resultados que van con varios o muchos decimales, sin importar cómo almacenes los números. El problema es cómo presentar el resultado.

Si su resultado está en el límite entre ser redondeado hacia arriba y hacia abajo, y ese último centavo realmente importa, probablemente debería decirle al espectador que la respuesta está casi en el medio, al mostrar más lugares decimales.

El problema con los dobles, y más con los flotadores, es cuando se usan para combinar números grandes y pequeños. En java

System.out.println(1000000.0f + 1.2f - 1000000.0f);

resultados en

1.1875


Flotantes y dobles son aproximados. Si creas un BigDecimal y pasas un flotador al constructor, verás lo que realmente es el flotante:

groovy:000> new BigDecimal(1.0F) ===> 1 groovy:000> new BigDecimal(1.01F) ===> 1.0099999904632568359375

Probablemente no sea así como quieres representar $ 1.01.

El problema es que la especificación IEEE no tiene una manera de representar exactamente todas las fracciones, algunas de ellas terminan como fracciones repetidas, por lo que terminas con errores de aproximación. Dado que a los contadores les gusta que las cosas salgan exactamente al centavo, y los clientes se sentirán molestos si pagan su factura y una vez que se procesa el pago, deben .01 y se les cobra una tarifa o no pueden cerrar su cuenta, es mejor usar Tipos exactos como decimal (en C #) o java.math.BigDecimal en Java.

No es que el error no sea controlable si redondeas: consulta este artículo de Peter Lawrey . Simplemente es más fácil no tener que redondear en primer lugar. La mayoría de las aplicaciones que manejan dinero no requieren muchos cálculos matemáticos, las operaciones consisten en agregar cosas o asignar cantidades a diferentes categorías. La introducción del punto flotante y el redondeo simplemente complica las cosas.


La mayoría de las respuestas han resaltado las razones por las que uno no debe usar dobles para los cálculos de dinero y moneda. Y estoy totalmente de acuerdo con ellos.

Sin embargo, no significa que los dobles nunca puedan usarse para ese propósito.

He trabajado en varios proyectos con requisitos de GC muy bajos, y tener objetos BigDecimal fue un gran contribuyente a esa sobrecarga.

Es la falta de comprensión acerca de la doble representación y la falta de experiencia en el manejo de la precisión y la precisión que produce esta sugerencia inteligente.

Puede hacerlo funcionar si puede manejar la precisión y los requisitos de precisión de su proyecto, lo que debe hacerse en función de qué rango de valores dobles se trata.

Puede consultar el método FuzzyCompare de la guayaba para tener una idea más clara. La tolerancia del parámetro es la clave. Tratamos este problema para una aplicación de negociación de valores e hicimos una investigación exhaustiva sobre qué tolerancias usar para diferentes valores numéricos en diferentes rangos.

Además, puede haber situaciones en las que tengas la tentación de usar envoltorios dobles como una clave de mapa con el mapa hash como la implementación. Es muy arriesgado porque Double.equals y el código hash para los valores de ejemplo "0.5" y "0.6 - 0.1" causarán un gran desorden.


Me arriesgaré a ser votado, pero creo que la inadecuación de los números de punto flotante para los cálculos de moneda está sobrevaluada. Mientras se asegure de hacer el redondeo de los centavos correctamente y tenga suficientes dígitos significativos para trabajar para contrarrestar la falta de coincidencia de la representación decimal-binaria explicada por zneak, no habrá problema.

Las personas que calculan con moneda en Excel siempre han usado flotadores de doble precisión (no hay tipo de moneda en Excel) y todavía no he visto a nadie quejándose de errores de redondeo.

Por supuesto, tienes que estar dentro de la razón; por ejemplo, una tienda web simple probablemente nunca experimentará ningún problema con flotadores de doble precisión, pero si lo hace, por ejemplo, contabilidad o cualquier otra cosa que requiera agregar una gran cantidad de números (no restringidos), no querría tocar números de punto flotante con un pie de diez pies. polo.


Muchas de las respuestas publicadas a esta pregunta tratan sobre IEEE y los estándares que rodean la aritmética de punto flotante.

Con una formación no informática (física e ingeniería), tiendo a considerar los problemas desde una perspectiva diferente. Para mí, la razón por la que no usaría doble o flotar en un cálculo matemático es porque perdería demasiada información.

¿Cuáles son las alternativas? Hay muchos (y muchos más de los cuales no estoy enterado).

BigDecimal en Java es nativo del lenguaje Java. Apfloat es otra biblioteca de precisión arbitraria para Java.

El tipo de datos decimales en C # es la alternativa .NET de Microsoft para 28 cifras significativas.

SciPy (Scientific Python) probablemente también puede manejar cálculos financieros (no lo he intentado, pero sospecho que sí).

La biblioteca de precisión múltiple (GMP) de GNU y la biblioteca MFPR de GNU son dos recursos gratuitos y de código abierto para C y C ++.

También hay bibliotecas de precisión numérica para JavaScript (!) Y creo que PHP puede manejar cálculos financieros.

También hay soluciones propietarias (particularmente, creo, para Fortran) y de código abierto, así como para muchos lenguajes informáticos.

No soy un informático en formación. Sin embargo, tiendo a inclinarme hacia BigDecimal en Java o decimal en C #. No he probado las otras soluciones que he enumerado, pero probablemente también sean muy buenas.

Para mí, me gusta BigDecimal debido a los métodos que soporta. El decimal de C # es muy bueno, pero no he tenido la oportunidad de trabajar con él tanto como me gustaría. Hago cálculos científicos que me interesan en mi tiempo libre, y BigDecimal parece funcionar muy bien porque puedo establecer la precisión de mis números de punto flotante. ¿La desventaja de BigDecimal? Puede ser lento a veces, especialmente si está utilizando el método de división.

Para la velocidad, puede buscar en las bibliotecas gratuitas y propietarias de C, C ++ y Fortran.


Porque los flotadores y los dobles no pueden representar con precisión los múltiplos base 10 que usamos para obtener dinero. Este problema no es solo para Java, es para cualquier lenguaje de programación que use tipos de punto flotante base 2.

En la base 10, puede escribir 10.25 como 1025 * 10 -2 (un entero por una potencia de 10). Los números de punto flotante IEEE-754 son diferentes, pero una forma muy simple de pensar en ellos es multiplicar por una potencia de dos. Por ejemplo, podría estar mirando 164 * 2 -4 (un entero por una potencia de dos), que también es igual a 10.25. No es así como se representan los números en la memoria, pero las implicaciones matemáticas son las mismas.

Incluso en la base 10, esta notación no puede representar con precisión las fracciones más simples. Por ejemplo, no puede representar 1/3: la representación decimal se repite (0.3333 ...), por lo que no hay un entero finito que pueda multiplicar por una potencia de 10 para obtener 1/3. Podría establecerse en una larga secuencia de 3 y un pequeño exponente, como 333333333 * 10 -10 , pero no es exacto: si multiplica eso por 3, no obtendrá 1.

Sin embargo, con el fin de contar el dinero, al menos para los países cuyo dinero se valora en un orden de magnitud del dólar estadounidense, generalmente todo lo que necesita es poder almacenar múltiplos de 10 -2 , por lo que realmente no importa ese 1/3 no puede ser representado.

El problema con los flotantes y los dobles es que la gran mayoría de los números de tipo monetario no tienen una representación exacta, ya que un entero por una potencia de 2. De hecho, los únicos múltiplos de 0.01 entre 0 y 1 (que son significativos cuando se trata de con dinero porque son céntimos enteros) que pueden representarse exactamente como un número binario de punto flotante IEEE-754 que son 0, 0.25, 0.5, 0.75 y 1. Todos los demás están desactivados en una pequeña cantidad. Como analogía con el ejemplo 0.333333, si toma el valor de punto flotante para 0.1 y lo multiplica por 10, no obtendrá 1.

Representar el dinero como double o float probablemente se verá bien al principio, ya que el software redondea los pequeños errores, pero a medida que realiza más sumas, restas, multiplicaciones y divisiones en números inexactos, los errores se agravarán y terminará con valores que Visiblemente no son precisos. Esto hace que los flotadores y los dobles sean inadecuados para tratar con el dinero, donde se requiere una precisión perfecta para múltiplos de poderes de base 10.

Una solución que funciona en casi cualquier idioma es usar enteros y contar los centavos. Por ejemplo, 1025 sería $ 10.25. Varios idiomas también tienen tipos incorporados para tratar con el dinero. Entre otros, Java tiene la clase BigDecimal y C # tiene el tipo decimal .


Prefiero usar Integer o Long para representar la moneda. BigDecimal junks el código fuente demasiado.

Solo tienes que saber que todos tus valores están en centavos. O el valor más bajo de cualquier moneda que estés usando.


Si bien es cierto que el tipo de punto flotante puede representar solo datos aproximadamente decimales, también es cierto que si uno redondea los números a la precisión necesaria antes de presentarlos, obtiene el resultado correcto. Generalmente.

Normalmente porque el tipo doble tiene una precisión inferior a 16 cifras. Si necesita una mejor precisión no es un tipo adecuado. También se pueden acumular aproximaciones.

Debe decirse que incluso si usa la aritmética de punto fijo, todavía tiene que redondear los números, si no fuera por el hecho de que BigInteger y BigDecimal dan errores si obtiene números decimales periódicos. Así que hay una aproximación también aquí.

Por ejemplo, COBOL, utilizado históricamente para cálculos financieros, tiene una precisión máxima de 18 cifras. Así que a menudo hay un redondeo implícito.

En conclusión, en mi opinión, el doble no es adecuado principalmente por su precisión de 16 dígitos, que puede ser insuficiente, no porque sea aproximado.

Considere la siguiente salida del programa posterior. Muestra que después del redondeo doble da el mismo resultado que BigDecimal hasta la precisión 16.

Precision 14 ------------------------------------------------------ BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result. DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5 BigDecimal : 56789.012345 / 1111111111 = 0.000051110111115611 Double : 56789.012345 / 1111111111 = 0.000051110111115611 Precision 15 ------------------------------------------------------ BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result. DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5 BigDecimal : 56789.012345 / 1111111111 = 0.0000511101111156110 Double : 56789.012345 / 1111111111 = 0.0000511101111156110 Precision 16 ------------------------------------------------------ BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result. DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5 BigDecimal : 56789.012345 / 1111111111 = 0.00005111011111561101 Double : 56789.012345 / 1111111111 = 0.00005111011111561101 Precision 17 ------------------------------------------------------ BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result. DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5 BigDecimal : 56789.012345 / 1111111111 = 0.000051110111115611011 Double : 56789.012345 / 1111111111 = 0.000051110111115611013 Precision 18 ------------------------------------------------------ BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result. DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5 BigDecimal : 56789.012345 / 1111111111 = 0.0000511101111156110111 Double : 56789.012345 / 1111111111 = 0.0000511101111156110125 Precision 19 ------------------------------------------------------ BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result. DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5 BigDecimal : 56789.012345 / 1111111111 = 0.00005111011111561101111 Double : 56789.012345 / 1111111111 = 0.00005111011111561101252

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.MathContext; public class Exercise { public static void main(String[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { String amount = "56789.012345"; String quantity = "1111111111"; int [] precisions = new int [] {14, 15, 16, 17, 18, 19}; for (int i = 0; i < precisions.length; i++) { int precision = precisions[i]; System.out.println(String.format("Precision %d", precision)); System.out.println("------------------------------------------------------"); execute("BigDecimalNoRound", amount, quantity, precision); execute("DoubleNoRound", amount, quantity, precision); execute("BigDecimal", amount, quantity, precision); execute("Double", amount, quantity, precision); System.out.println(); } } private static void execute(String test, String amount, String quantity, int precision) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method impl = Exercise.class.getMethod("divideUsing" + test, String.class, String.class, int.class); String price; try { price = (String) impl.invoke(null, amount, quantity, precision); } catch (InvocationTargetException e) { price = e.getTargetException().getMessage(); } System.out.println(String.format("%-30s: %s / %s = %s", test, amount, quantity, price)); } public static String divideUsingDoubleNoRound(String amount, String quantity, int precision) { // acceptance double amount0 = Double.parseDouble(amount); double quantity0 = Double.parseDouble(quantity); //calculation double price0 = amount0 / quantity0; // presentation String price = Double.toString(price0); return price; } public static String divideUsingDouble(String amount, String quantity, int precision) { // acceptance double amount0 = Double.parseDouble(amount); double quantity0 = Double.parseDouble(quantity); //calculation double price0 = amount0 / quantity0; // presentation MathContext precision0 = new MathContext(precision); String price = new BigDecimal(price0, precision0) .toString(); return price; } public static String divideUsingBigDecimal(String amount, String quantity, int precision) { // acceptance BigDecimal amount0 = new BigDecimal(amount); BigDecimal quantity0 = new BigDecimal(quantity); MathContext precision0 = new MathContext(precision); //calculation BigDecimal price0 = amount0.divide(quantity0, precision0); // presentation String price = price0.toString(); return price; } public static String divideUsingBigDecimalNoRound(String amount, String quantity, int precision) { // acceptance BigDecimal amount0 = new BigDecimal(amount); BigDecimal quantity0 = new BigDecimal(quantity); //calculation BigDecimal price0 = amount0.divide(quantity0); // presentation String price = price0.toString(); return price; } }


Si su cálculo implica varios pasos, la aritmética de precisión arbitraria no lo cubrirá al 100%.

La única forma confiable de usar la representación perfecta de los resultados (use un tipo de datos de Fracción personalizado que repartirá las operaciones de división en el último paso) y solo se convertirá a una notación decimal en el último paso.

La precisión arbitraria no ayudará porque siempre puede haber números con tantos lugares decimales, o algunos resultados como 0.6666666 ... Ninguna representación arbitraria cubrirá el último ejemplo. Así tendrás pequeños errores en cada paso.

Estos errores se acumularán y, finalmente, pueden no ser fáciles de ignorar. Esto se llama Propagación de errores .


De Bloch, J., Effective Java, 2nd ed, Item 48:

Los tipos float y double son particularmente inadecuados para los cálculos monetarios porque es imposible representar 0.1 (o cualquier otra potencia negativa de diez) como float o double exactamente.

Por ejemplo, suponga que tiene $ 1.03 y gasta 42c. ¿Cuánto dinero te queda?

System.out.println(1.03 - .42);

imprime 0.6100000000000001 .

La forma correcta de resolver este problema es usar BigDecimal , int o long para cálculos monetarios.


Algunos ejemplos ... esto funciona (en realidad no funciona como se esperaba), en casi cualquier lenguaje de programación ... Lo he intentado con Delphi, VBScript, Visual Basic, JavaScript y ahora con Java / Android:

double total = 0.0; // do 10 adds of 10 cents for (int i = 0; i < 10; i++) { total += 0.1; // adds 10 cents } Log.d("round problems?", "current total: " + total); // looks like total equals to 1.0, don''t? // now, do reverse for (int i = 0; i < 10; i++) { total -= 0.1; // removes 10 cents } // looks like total equals to 0.0, don''t? Log.d("round problems?", "current total: " + total); if (total == 0.0) { Log.d("round problems?", "is total equal to ZERO? YES, of course!!"); } else { Log.d("round problems?", "is total equal to ZERO? NO... thats why you should not use Double for some math!!!"); }

SALIDA:

round problems?: current total: 0.9999999999999999 round problems?: current total: 2.7755575615628914E-17 round problems?: is total equal to ZERO? NO... thats why you should not use Double for some math!!!