que punto numeros notación normalizado normalizada norma mantisa informatica flotante ejemplos coma java floating-point

java - punto - La aritmética de coma flotante no produce resultados exactos



punto flotante plc (7)

Desde un punto de vista filosófico, me pregunto: la mayoría de las CPU de la computadora de hoy en día tienen soporte incorporado para la aritmética de enteros y la aritmética de coma flotante, pero no admiten la aritmética decimal. Por qué no? No he escrito una solicitud en años en que los flotadores eran utilizables debido a este problema de redondeo. Ciertamente no puede usarlos por montos de dinero: nadie quiere imprimir un precio en un recibo de venta de "$ 42.3200003". Ningún contador va a aceptar que "podríamos perder un centavo aquí y allá porque estamos usando fracciones binarias y teníamos errores de redondeo".

Los flotadores están bien para mediciones, como la distancia o la temperatura, donde no existe una "respuesta exacta" y debes redondear a la precisión de tus instrumentos en algún punto de todos modos. Supongo que para las personas que están programando la computadora en el laboratorio de química, las carrozas se usan rutinariamente. Pero para aquellos de nosotros en el mundo de los negocios, son bastante inútiles.

En aquellos tiempos antiguos cuando programé en mainframes, la familia de CPU IBM 360 tenía soporte incorporado para la aritmética decimal empaquetada. Almacenaron cadenas donde cada byte contenía dos dígitos decimales, es decir, los primeros cuatro bits tenían valores de 0 a 9 y lo mismo pasaban con los segundos cuatro bits, y la CPU tenía funciones aritméticas para manipularlos. ¿Por qué Intel no puede hacer algo como eso? Entonces Java podría agregar un tipo de datos "decimal" y no necesitaríamos toda la basura extra.

No estoy diciendo que abolir las carrozas, por supuesto. Solo agrega decimales.

Bueno, como van los grandes movimientos sociales, no creo que esto genere mucha agitación popular o disturbios en las calles.

Esta pregunta ya tiene una respuesta aquí:

Necesito hacer aritmética en coma flotante en Java como se muestra en el siguiente código:

public class TestMain { private static Map<Integer, Double> ccc = new HashMap<Integer, Double>() { { put(1, 0.01); put(2, 0.02); put(3, 0.05); put(4, 0.1); put(6, 0.2); put(10, 0.5); put(20, 1.0); put(30, 2.0); put(50, 5.0); put(100, 10.0); } }; Double increment(Double i, boolean up) { Double inc = null; while (inc == null) { inc = ccc.get(i.intValue()); if (up) --i; else ++i; } return inc; } public static void main(String[] args) { TestMain tt = new TestMain(); for (double i = 1; i < 1000; i += tt.increment(i, true)) { System.out.print(i + ","); } } }

Esto es para simular el rango de valores dado como salida por el widget de spinner de Betfair .

La aritmética de coma flotante en Java parece presentar algunos errores inesperados. Por ejemplo, obtengo 2.180000000000001 en vez de 2.18. ¿De qué sirven los números de coma flotante si no puede confiar en los resultados de la aritmética realizada en ellos? ¿Cómo puedo evitar este problema?


Los números de coma flotante son imprecisos, especialmente porque funcionan en fracciones binarias (1/2, 1/4, 1/8, 1/16, 1/32, ...) en lugar de fracciones decimales (1/10, 1 / 100, 1/1000, ...). Simplemente defina lo que siente que está "lo suficientemente cerca" y use algo como Math.abs(ab) < 0.000001 .


Los números de coma flotante usan fracciones binarias y no fracciones decimales. Es decir, está acostumbrado a fracciones decimales formadas por un dígito de décimas, un dígito de centésimas, un dígito de milésimas, etc. d1 / 10 + d2 / 100 + d3 / 1000 ... Pero los números de coma flotante están en binario, por lo que tienen medio dígito, un cuarto de dígito, un octavo dígito, etc. d1 / 2 + d2 / 4 + d3 / 8 ...

Muchas fracciones decimales no se pueden expresar exactamente en ningún número finito de dígitos binarios. Por ejemplo, 1/2 no es problema: en decimal es .5, en binario es .1. 3/4 es decimal .75, binario .11. Pero 1/10 es un .1 en decimal, pero en binario es .0001100110011 ... con el "0011" repitiendo para siempre. Como la computadora puede almacenar solo un número finito de dígitos, en algún momento esto tiene que cortarse, por lo que la respuesta no es precisa. Cuando convertimos de nuevo a decimal en la salida, obtenemos un número de aspecto extraño.

Como dice Jon Skeet, si necesita fracciones decimales exactas, use BigDecimal. Si el rendimiento es un problema, puede tirar sus propias fracciones decimales. Por ejemplo, si sabes que siempre quieres exactamente 3 lugares decimales y que los números no serán más de un millón, podrías simplemente usar int con un supuesto 3 decimales, haciendo los ajustes necesarios cuando haces aritmética y escribes una salida función de formato para insertar el punto decimal en el lugar correcto. Pero el rendimiento del 99% del tiempo no es un problema lo suficientemente grande como para valer la pena.


Por cierto, puede tratar de usar esta función para asegurarse (para no demasiados dígitos decimales) de que su número será reformateado para mantener solo los decimales que necesita.

http://pastebin.com/CACER0xK

n es tu número con muchos decimales (por ejemplo, Math.PI ), numberOfDecimals es la cantidad máxima de decimales que necesitas (por ejemplo, 2 para 3.14 o 3 para 3.151).

Por teoría, al poner un valor negativo a numberOfDecmals , también cortará los dígitos enteros inferiores del número. Poniendo n=1588.22 y numberOfDecimals=-2 , la función devolverá 1500.0 .

Avísame si es algo malo.


Puede escribir un código para calcular Epsilon en su máquina. Creo que std :: C ++ lo define, se define de otras maneras dependiendo de lo que está usando.

private static float calcEpsilonFloat() { float epsi = 1.0f; while ((float) (1.0 + (epsi / 2.0)) != 1.0) { epsi /= 2.0f; } return epsi; }

La única vez que me preocupé por Epsilon fue cuando estaba comparando señales para el umbral. Incluso entonces no estoy seguro de que realmente deba preocuparme por ello, en mi experiencia, si está preocupado acerca de Epsilon, es posible que tenga que considerar primero otra consideración.


Puede hacer que la salida de su programa se vea más de lo que espera al usar salida formateada.

http://java.sun.com/javase/6/docs/api/java/util/Formatter.html

Obviamente, la aritmética de punto flotante subyacente sigue funcionando igual, pero al menos la salida será más legible.

Por ejemplo, para redondear los resultados a dos decimales:

System.out.print(String.format(".2f", i) + ",");