Cómo formatear muy bien números flotantes en cadenas sin ceros decimales innecesarios

Resuelto Pyrolistical asked hace 15 años • 29 respuestas

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).

Pyrolistical avatar Apr 01 '09 05:04 Pyrolistical
Aceptado

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.

JasonD avatar Jan 02 '2013 17:01 JasonD
String.format("%.2f", value);
Jeremy Slade avatar Aug 14 '2009 04:08 Jeremy Slade

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()o System.out.printlnusa FloatingDecimal.toJavaFormatStringnotaciones científicas si el doble es menor que 10^-3 o mayor o igual a 10^7

     double 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 %.0feliminando cualquier precisión decimal, lo cual está bien para números enteros/largos pero no para dobles

     double 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:

  • setMaximumFractionDigitsacepta un número entero, pero su implementación tiene un máximo de dígitos permitidos de DecimalFormat.DOUBLE_FRACTION_DIGITSlos cuales equivale a 340
  • Double.MIN_VALUE = 4.9E-324así que con 340 dígitos seguro que no redondeas tu doble y pierdes precisión
JBE avatar Aug 14 '2014 12:08 JBE