Entonces tengo un conjunto doble para igualar 1234, quiero mover un lugar decimal para que sea 12.34
Entonces, para hacer esto, multiplico .1 a 1234 dos veces, algo así
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.println(x);
Esto imprimirá el resultado, "12.340000000000002"
¿Hay alguna manera, sin simplemente formatearlo a dos lugares decimales, para que el doble almacene correctamente 12,34?
x /= 100;
?Respuestas:
Si usa
double
ofloat
, debe usar el redondeo o esperar ver algunos errores de redondeo. Si no puede hacer esto, useBigDecimal
.El problema que tiene es que 0,1 no es una representación exacta, y al realizar el cálculo dos veces, está agravando ese error.
Sin embargo, 100 se pueden representar con precisión, así que intente:
que imprime:
Esto funciona porque
Double.toString(d)
realiza una pequeña cantidad de redondeo en su nombre, pero no es mucho. Si se pregunta cómo se vería sin redondeo:huellas dactilares:
En resumen, el redondeo es inevitable para respuestas sensatas en punto flotante, ya sea que lo esté haciendo explícitamente o no.
Nota:
x / 100
yx * 0.01
no son exactamente iguales cuando se trata de error de redondeo. Esto se debe a que el error de redondeo de la primera expresión depende de los valores de x, mientras que el0.01
de la segunda tiene un error de redondeo fijo.huellas dactilares
fuente
1234/100
, como lo ha hecho, no hace nada sobre el problema subyacente; debería ser exactamente igual a escribir1234 * 0.01
./100
y*0.01
son equivalentes entre sí, pero no a los OP*0.1*0.1
.No, si desea almacenar valores decimales con precisión, utilice
BigDecimal
.double
simplemente no puede representar un número como 0.1 exactamente, como tampoco puede escribir el valor de un tercio exactamente con un número finito de dígitos decimales.fuente
si se acaba de formatear, printf
salida
fuente
System.out.printf()
es el camino correcto a seguir.En el software financiero, es común usar números enteros por monedas de un centavo. En la escuela, nos enseñaron cómo usar el punto fijo en lugar de flotante, pero eso suele ser potencias de dos. El almacenamiento de monedas de un centavo en números enteros también se puede llamar "punto fijo".
En clase, nos preguntaron en general qué números se pueden representar exactamente en una base.
Para
base=p1^n1*p2^n2
... puede representar cualquier N donde N = n * p1 ^ m1 * p2 ^ m2.Deja
base=14=2^1*7^1
... puedes representar 1/7 1/14 1/28 1/49 pero no 1/3Sé sobre software financiero: convertí los informes financieros de Ticketmaster de VAX asm a PASCAL. Tenían su propio formato () con códigos para monedas de un centavo. El motivo de la conversión fue que los números enteros de 32 bits ya no eran suficientes. +/- 2 mil millones de centavos son $ 20 millones y eso se desbordó para la Copa del Mundo o los Juegos Olímpicos, lo olvidé.
Juré guardar el secreto. Oh bien. En la academia, si es bueno publicas; en la industria, lo mantienes en secreto.
fuente
puedes probar la representación de números enteros
fuente
r
es menor que 10, no se produce ningún relleno de 0 y 1204 produciría un resultado de 12,4. La cadena de formato correcta es más similar a "% d.% 02d"Esto se debe a la forma en que las computadoras almacenan números de punto flotante. No lo hacen exactamente. Como programador, debe leer esta guía de punto flotante para familiarizarse con las pruebas y tribulaciones de manejar números de punto flotante.
fuente
¿Es curioso que numerosas publicaciones mencionen el uso de BigDecimal pero nadie se moleste en dar la respuesta correcta basada en BigDecimal? Porque incluso con BigDecimal, aún puede salir mal, como lo demuestra este código
Da esta salida
El constructor BigDecimal menciona específicamente que es mejor usar el constructor String que un constructor numérico. La precisión máxima también está influenciada por MathContext opcional.
De acuerdo con BigDecimal Javadoc , es posible crear un BigDecimal que sea exactamente igual a 0.1, siempre que use el constructor String.
fuente
Sí hay. Con cada operación doble puede perder precisión, pero la cantidad de precisión difiere para cada operación y puede minimizarse eligiendo la secuencia correcta de operaciones. Por ejemplo, al multiplicar un conjunto de números, es mejor ordenar el conjunto por exponente antes de multiplicar.
Cualquier libro decente sobre cálculo numérico describe esto. Por ejemplo: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Y para responder a tu pregunta:
Use dividir en lugar de multiplicar, de esta manera obtendrá el resultado correcto.
fuente
No, ya que los tipos de coma flotante de Java (de hecho, todos los tipos de coma flotante) son un compromiso entre tamaño y precisión. Si bien son muy útiles para muchas tareas, si necesita precisión arbitraria, debe usar
BigDecimal
.fuente