public class doublePrecision {
public static void main(String[] args) {
double total = 0;
total += 5.6;
total += 5.8;
System.out.println(total);
}
}
Se imprime el código anterior:
11.399999999999
¿Cómo conseguiría que esto simplemente imprima (o pueda usarlo como) 11.4?
java
floating-point
double
precision
Deinumita
fuente
fuente
Respuestas:
Como otros han mencionado, probablemente querrás usar el
BigDecimal
clase, si quieres tener una representación exacta de 11.4.Ahora, una pequeña explicación de por qué sucede esto:
Los tipos
float
ydouble
primitivos en Java son números de coma flotante , donde el número se almacena como una representación binaria de una fracción y un exponente.Más específicamente, un valor de coma flotante de doble precisión como el
double
tipo es un valor de 64 bits, donde:Estas partes se combinan para producir una
double
representación de un valor.(Fuente: Wikipedia: Doble precisión )
Para obtener una descripción detallada de cómo se manejan los valores de punto flotante en Java, consulte la Sección 4.2.3: Tipos, formatos y valores de punto flotante de la Especificación del lenguaje Java.
Los
byte
,char
,int
,long
tipos son de punto fijo números, que son representions exactas de números. A diferencia de los números de punto fijo, los números de coma flotante algunas veces (es seguro asumir "la mayoría de las veces") no podrán devolver una representación exacta de un número. Esta es la razón por la que terminas11.399999999999
como resultado de5.6 + 5.8
.Cuando requiera un valor exacto, como 1.5 o 150.1005, querrá usar uno de los tipos de punto fijo, que podrá representar el número exactamente.
Como ya se ha mencionado varias veces, Java tiene una
BigDecimal
clase que manejará números muy grandes y números muy pequeños.De la referencia de la API de Java para la
BigDecimal
clase:Ha habido muchas preguntas sobre Stack Overflow relacionadas con la cuestión de los números de coma flotante y su precisión. Aquí hay una lista de preguntas relacionadas que pueden ser de interés:
Si realmente quiere llegar a los detalles esenciales de los números de coma flotante, eche un vistazo a Lo que todo informático debe saber sobre la aritmética de coma flotante .
fuente
BigDecimal
es mucho más lento quedouble
en este caso, no es necesario ya que el doble tiene 15 decimales de precisión, solo necesita redondear.Cuando ingresa un número doble, por ejemplo,
33.33333333333333
el valor que obtiene es en realidad el valor de doble precisión representable más cercano, que es exactamente:Dividiendo eso por 100 da:
que tampoco es representable como un número de doble precisión, por lo que nuevamente se redondea al valor representable más cercano, que es exactamente:
Cuando imprime este valor, se redondea una vez más a 17 dígitos decimales, dando:
fuente
Si solo desea procesar valores como fracciones, puede crear una clase de fracciones que contenga un campo numerador y denominador.
Escriba métodos para sumar, restar, multiplicar y dividir, así como un método toDouble. De esta manera puede evitar flotadores durante los cálculos.
EDITAR: Implementación rápida,
fuente
numerator
ydenominator
debe serint
s? ¿Por qué querrías precisión de punto flotante?Observe que tendría el mismo problema si utilizara la aritmética decimal de precisión limitada y quisiera tratar con 1/3: 0.333333333 * 3 es 0.999999999, no 1.00000000.
Desafortunadamente, 5.6, 5.8 y 11.4 simplemente no son números redondos en binario, porque involucran quintos. Entonces la representación flotante de ellos no es exacta, así como 0.3333 no es exactamente 1/3.
Si todos los números que usa son decimales no recurrentes y desea resultados exactos, use BigDecimal. O como han dicho otros, si sus valores son como el dinero en el sentido de que todos son múltiplos de 0.01, o 0.001, o algo así, multiplique todo por una potencia fija de 10 y use int o long (suma y resta son trivial: cuidado con la multiplicación).
Sin embargo, si está satisfecho con el binario para el cálculo, pero solo desea imprimir las cosas en un formato un poco más amigable, intente
java.util.Formatter
oString.format
. En la cadena de formato, especifique una precisión menor que la precisión completa de un doble. Para 10 cifras significativas, digamos, 11.399999999999 es 11.4, por lo que el resultado será casi tan preciso y más legible para los humanos en los casos en que el resultado binario esté muy cerca de un valor que requiera solo unos pocos decimales.La precisión para especificar depende un poco de la cantidad de matemáticas que haya hecho con sus números; en general, cuanto más lo haga, más error se acumulará, pero algunos algoritmos lo acumulan mucho más rápido que otros (se llaman "inestables" como opuesto a "estable" con respecto a los errores de redondeo). Si todo lo que está haciendo es agregar algunos valores, entonces supongo que soltar solo un lugar decimal de precisión resolverá las cosas. Experimentar.
fuente
Es posible que desee considerar el uso de la clase java.math.BigDecimal de java si realmente necesita matemática de precisión. Aquí hay un buen artículo de Oracle / Sun sobre el caso de BigDecimal . Si bien nunca puedes representar 1/3 como alguien mencionó, puedes tener el poder de decidir exactamente qué tan preciso desea que sea el resultado. setScale () es tu amigo .. :)
Ok, porque tengo mucho tiempo libre en este momento, aquí hay un ejemplo de código que se relaciona con su pregunta:
y para conectar mi nuevo idioma favorito, Groovy, aquí hay un ejemplo más ordenado de lo mismo:
fuente
Estoy bastante seguro de que podrías haber hecho eso en un ejemplo de tres líneas. :)
Si desea precisión exacta, use BigDecimal. De lo contrario, puede usar ints multiplicados por 10 ^ cualquier precisión que desee.
fuente
Como otros han señalado, no todos los valores decimales se pueden representar como binarios, ya que el decimal se basa en potencias de 10 y el binario se basa en potencias de dos.
Si la precisión es importante, usa BigDecimal, pero si solo quieres una salida amigable:
Te regalaré:
fuente
Estás corriendo contra la limitación de precisión del tipo doble.
Java.Math tiene algunas facilidades aritméticas de precisión arbitraria.
fuente
No puede, porque 7.3 no tiene una representación finita en binario. Lo más cercano que puede obtener es 2054767329987789/2 ** 48 = 7.3 + 1/1407374883553280.
Echa un vistazo a http://docs.python.org/tutorial/floatingpoint.html para obtener una explicación más detallada. (Está en el sitio web de Python, pero Java y C ++ tienen el mismo "problema").
La solución depende de cuál sea exactamente su problema:
fuente
fuente
Use java.math.BigDecimal
Los dobles son fracciones binarias internamente, por lo que a veces no pueden representar fracciones decimales al decimal exacto.
fuente
Multiplique todo por 100 y guárdelo en centavos.
fuente
Las computadoras almacenan números en binario y en realidad no pueden representar números como 33.333333333 o 100.0 exactamente. Esta es una de las cosas difíciles sobre el uso de dobles. Tendrá que redondear la respuesta antes de mostrársela a un usuario. Afortunadamente, en la mayoría de las aplicaciones, no necesita tantos decimales de todos modos.
fuente
Los números de coma flotante difieren de los números reales en que para cualquier número de coma flotante hay un siguiente número de coma flotante más alto. Igual que los enteros. No hay un número entero entre 1 y 2.
No hay forma de representar 1/3 como flotante. Hay un flotador debajo y hay un flotador encima, y hay una cierta distancia entre ellos. Y 1/3 está en ese espacio.
Apfloat para Java afirma que funciona con números de coma flotante de precisión arbitraria, pero nunca lo he usado. Probablemente vale la pena echarle un vistazo. http://www.apfloat.org/apfloat_java/
Aquí se hizo una pregunta similar antes de la biblioteca de alta precisión de coma flotante de Java
fuente
Los dobles son aproximaciones de los números decimales en su fuente Java. Está viendo la consecuencia de la falta de coincidencia entre el doble (que es un valor codificado en binario) y su fuente (que está codificada en decimal).
Java produce la aproximación binaria más cercana. Puede usar java.text.DecimalFormat para mostrar un valor decimal más atractivo.
fuente
Utiliza un BigDecimal. Incluso le permite especificar reglas de redondeo (como ROUND_HALF_EVEN, que minimizará el error estadístico al redondear al vecino par si ambos tienen la misma distancia; es decir, tanto 1.5 como 2.5 redondean a 2).
fuente
Respuesta corta: siempre usa BigDecimal y asegúrate de estar usando el constructor con el argumento String , no el doble.
Volviendo a su ejemplo, el siguiente código imprimirá 11.4, como lo desee.
fuente
Echa un vistazo a BigDecimal, maneja problemas relacionados con la aritmética de coma flotante como esa.
La nueva llamada se vería así:
Use setScale () para establecer el número de precisión de lugar decimal que se utilizará.
fuente
¿Por qué no usar el método round () de la clase de matemáticas?
fuente
Si no tiene otra opción que no sea usar valores dobles, puede usar el siguiente código.
fuente
No malgastes tu efford usando BigDecimal. En el 99.99999% de los casos no lo necesita. Java Double Type es de origen aproximado pero en casi todos los casos, es lo suficientemente preciso. Tenga en cuenta que tiene un error en el decimocuarto dígito significativo.¡Esto es realmente insignificante!
Para obtener un buen resultado de uso:
fuente