Cómo formatear muy bien números flotantes en cadenas sin ceros decimales innecesarios
Un doble de 64 bits puede representar un número entero +/- 2 53 exactamente.
Dado este hecho, elijo utilizar un tipo doble como tipo único para todos mis tipos, ya que mi entero más grande es un número de 32 bits sin signo.
Pero ahora tengo que imprimir estos pseudoenteros, pero el problema es que también están mezclados con dobles reales.
Entonces, ¿cómo imprimo bien estos dobles en Java?
Lo intenté String.format("%f", value)
, lo cual está cerca, excepto que obtengo muchos ceros finales para valores pequeños.
Aquí hay un ejemplo de salida de of%f
232.00000000 0.18000000000 1237875192.0 4.5800000000 0.00000000 1.23450000
Lo que quiero es:
232 0,18 1237875192 4.58 0 1.2345
Seguro que puedo escribir una función para recortar esos ceros, pero eso supone una gran pérdida de rendimiento debido a la manipulación de cadenas. ¿Puedo hacerlo mejor con otro código de formato?
Las respuestas de Tom E. y Jeremy S. son inaceptables ya que ambos redondean arbitrariamente a dos decimales. Por favor, comprenda el problema antes de responder.
Tenga en cuenta que String.format(format, args...)
depende de la configuración regional (consulte las respuestas a continuación).
Si la idea es imprimir números enteros almacenados como dobles como si fueran números enteros, y en caso contrario imprimir los dobles con la mínima precisión necesaria:
public static String fmt(double d)
{
if(d == (long) d)
return String.format("%d",(long)d);
else
return String.format("%s",d);
}
Produce:
232
0.18
1237875192
4.58
0
1.2345
Y no depende de la manipulación de cadenas.
String.format("%.2f", value);
En breve:
Si desea deshacerse de los ceros finales y los problemas de configuración regional , debe utilizar:
double myValue = 0.00000021d;
DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340); //340 = DecimalFormat.DOUBLE_FRACTION_DIGITS
System.out.println(df.format(myValue)); //output: 0.00000021
Explicación:
Por qué otras respuestas no me convenían:
Double.toString()
oSystem.out.println
usaFloatingDecimal.toJavaFormatString
notaciones científicas si el doble es menor que 10^-3 o mayor o igual a 10^7double myValue = 0.00000021d; String.format("%s", myvalue); //output: 2.1E-7
al usar
%f
, la precisión decimal predeterminada es 6; de lo contrario, puede codificarla, pero se agregarán ceros adicionales si tiene menos decimales. Ejemplo:double myValue = 0.00000021d; String.format("%.12f", myvalue); // Output: 0.000000210000
usando
setMaximumFractionDigits(0);
o%.0f
eliminando cualquier precisión decimal, lo cual está bien para números enteros/largos pero no para doblesdouble myValue = 0.00000021d; System.out.println(String.format("%.0f", myvalue)); // Output: 0 DecimalFormat df = new DecimalFormat("0"); System.out.println(df.format(myValue)); // Output: 0
Al utilizar DecimalFormat, eres dependiente local. En la configuración regional francesa, el separador decimal es una coma, no un punto:
double myValue = 0.00000021d; DecimalFormat df = new DecimalFormat("0"); df.setMaximumFractionDigits(340); System.out.println(df.format(myvalue)); // Output: 0,00000021
El uso de la configuración regional INGLÉS garantiza que obtenga un punto para el separador decimal, dondequiera que se ejecute su programa.
¿Por qué usar 340 entonces setMaximumFractionDigits
?
Dos razones:
setMaximumFractionDigits
acepta un número entero, pero su implementación tiene un máximo de dígitos permitidos deDecimalFormat.DOUBLE_FRACTION_DIGITS
los cuales equivale a 340Double.MIN_VALUE = 4.9E-324
así que con 340 dígitos seguro que no redondeas tu doble y pierdes precisión