round redondear limitar float decimales con java string floating-point format double

redondear - math.round java dos decimales



¿Cómo formatear bien los números flotantes a Cadena sin decimal innecesario 0? (22)

Un doble de 64 bits puede representar un entero +/- 2 53 exactamente

Dado este hecho, elijo usar un tipo doble como un solo tipo para todos mis tipos, ya que mi entero más grande es sin signo de 32 bits.

Pero ahora tengo que imprimir estos pseudo enteros, pero el problema es que también se mezclan con los dobles reales.

Entonces, ¿cómo puedo imprimir estos dobles muy bien en Java?

He intentado String.format("%f", value) , que está cerca, excepto que obtengo muchos ceros finales para valores pequeños.

Aquí hay un ejemplo de salida de %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

Claro que puedo escribir una función para recortar esos ceros, pero eso es una gran pérdida de rendimiento debido a la manipulación de cadenas. ¿Puedo hacerlo mejor con otro código de formato?

EDITAR

Las respuestas de Tom E. y Jeremy S. son inaceptables, ya que ambas se redondean arbitrariamente a dos decimales. Por favor, comprenda el problema antes de responder.

Editar 2

Tenga en cuenta que String.format(format, args...) depende de la configuración regional (consulte las respuestas a continuación).


Aquí hay dos maneras de lograrlo. Primero, la forma más corta (y probablemente mejor):

public static String formatFloatToString(final float f) { final int i=(int)f; if(f==i) return Integer.toString(i); return Float.toString(f); }

Y aquí está la manera más larga y probablemente peor:

public static String formatFloatToString(final float f) { final String s=Float.toString(f); int dotPos=-1; for(int i=0;i<s.length();++i) if(s.charAt(i)==''.'') { dotPos=i; break; } if(dotPos==-1) return s; int end=dotPos; for(int i=dotPos+1;i<s.length();++i) { final char c=s.charAt(i); if(c!=''0'') end=i+1; } final String result=s.substring(0,end); return result; }


Aquí hay una respuesta que realmente funciona (combinación de respuestas diferentes aquí)

public static String removeTrailingZeros(double f) { if(f == (int)f) { return String.format("%d", (int)f); } return String.format("%f", f).replaceAll("0*$", ""); }


En mi máquina, la siguiente función es aproximadamente 7 veces más rápida que la función proporcionada por la respuesta de JasonD , ya que evita String.format :

public static String prettyPrint(double d) { int i = (int) d; return d == i ? String.valueOf(i) : String.valueOf(d); }


Este hará bien el trabajo, sé que el tema es viejo, pero estuve luchando con el mismo problema hasta que llegué a esto. Espero que alguien lo encuentre útil.

public static String removeZero(double number) { DecimalFormat format = new DecimalFormat("#.###########"); return format.format(number); }


Esto es lo que se me ocurrió:

private static String format(final double dbl) { return dbl % 1 != 0 ? String.valueOf(dbl) : String.valueOf((int) dbl); }

Simple un forro, solo se lanza a int si realmente se necesita


Hice un DoubleFormatter para convertir eficientemente una gran cantidad de valores dobles en una cadena agradable / presentable:

double horribleNumber = 3598945.141658554548844; DoubleFormatter df = new DoubleFormatter(4,6); //4 = MaxInteger, 6 = MaxDecimal String beautyDisplay = df.format(horribleNumber);

  • Si la parte entera de V tiene más de MaxInteger => muestra V en formato científico (1.2345e + 30), de lo contrario se muestra en formato normal 124.45678.
  • el MaxDecimal decide los números de dígitos decimales (recorte con redondeo bancario)

Aquí el código:

import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Locale; import com.google.common.base.Preconditions; import com.google.common.base.Strings; /** * Convert a double to a beautiful String (US-local): * * double horribleNumber = 3598945.141658554548844; * DoubleFormatter df = new DoubleFormatter(4,6); * String beautyDisplay = df.format(horribleNumber); * String beautyLabel = df.formatHtml(horribleNumber); * * Manipulate 3 instances of NumberFormat to efficiently format a great number of double values. * (avoid to create an object NumberFormat each call of format()). * * 3 instances of NumberFormat will be reused to format a value v: * * if v < EXP_DOWN, uses nfBelow * if EXP_DOWN <= v <= EXP_UP, uses nfNormal * if EXP_UP < v, uses nfAbove * * nfBelow, nfNormal and nfAbove will be generated base on the precision_ parameter. * * @author: DUONG Phu-Hiep */ public class DoubleFormatter { private static final double EXP_DOWN = 1.e-3; private double EXP_UP; // always = 10^maxInteger private int maxInteger_; private int maxFraction_; private NumberFormat nfBelow_; private NumberFormat nfNormal_; private NumberFormat nfAbove_; private enum NumberFormatKind {Below, Normal, Above} public DoubleFormatter(int maxInteger, int maxFraction){ setPrecision(maxInteger, maxFraction); } public void setPrecision(int maxInteger, int maxFraction){ Preconditions.checkArgument(maxFraction>=0); Preconditions.checkArgument(maxInteger>0 && maxInteger<17); if (maxFraction == maxFraction_ && maxInteger_ == maxInteger) { return; } maxFraction_ = maxFraction; maxInteger_ = maxInteger; EXP_UP = Math.pow(10, maxInteger); nfBelow_ = createNumberFormat(NumberFormatKind.Below); nfNormal_ = createNumberFormat(NumberFormatKind.Normal); nfAbove_ = createNumberFormat(NumberFormatKind.Above); } private NumberFormat createNumberFormat(NumberFormatKind kind) { final String sharpByPrecision = Strings.repeat("#", maxFraction_); //if you do not use Guava library, replace with createSharp(precision); NumberFormat f = NumberFormat.getInstance(Locale.US); //Apply banker''s rounding: this is the rounding mode that statistically minimizes cumulative error when applied repeatedly over a sequence of calculations f.setRoundingMode(RoundingMode.HALF_EVEN); if (f instanceof DecimalFormat) { DecimalFormat df = (DecimalFormat) f; DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); //set group separator to space instead of comma //dfs.setGroupingSeparator('' ''); //set Exponent symbol to minus ''e'' instead of ''E'' if (kind == NumberFormatKind.Above) { dfs.setExponentSeparator("e+"); //force to display the positive sign in the exponent part } else { dfs.setExponentSeparator("e"); } df.setDecimalFormatSymbols(dfs); //use exponent format if v is out side of [EXP_DOWN,EXP_UP] if (kind == NumberFormatKind.Normal) { if (maxFraction_ == 0) { df.applyPattern("#,##0"); } else { df.applyPattern("#,##0."+sharpByPrecision); } } else { if (maxFraction_ == 0) { df.applyPattern("0E0"); } else { df.applyPattern("0."+sharpByPrecision+"E0"); } } } return f; } public String format(double v) { if (Double.isNaN(v)) { return "-"; } if (v==0) { return "0"; } final double absv = Math.abs(v); if (absv<EXP_DOWN) { return nfBelow_.format(v); } if (absv>EXP_UP) { return nfAbove_.format(v); } return nfNormal_.format(v); } /** * format and higlight the important part (integer part & exponent part) */ public String formatHtml(double v) { if (Double.isNaN(v)) { return "-"; } return htmlize(format(v)); } /** * This is the base alogrithm: create a instance of NumberFormat for the value, then format it. It should * not be used to format a great numbers of value * * We will never use this methode, it is here only to understanding the Algo principal: * * format v to string. precision_ is numbers of digits after decimal. * if EXP_DOWN <= abs(v) <= EXP_UP, display the normal format: 124.45678 * otherwise display scientist format with: 1.2345e+30 * * pre-condition: precision >= 1 */ @Deprecated public String formatInefficient(double v) { final String sharpByPrecision = Strings.repeat("#", maxFraction_); //if you do not use Guava library, replace with createSharp(precision); final double absv = Math.abs(v); NumberFormat f = NumberFormat.getInstance(Locale.US); //Apply banker''s rounding: this is the rounding mode that statistically minimizes cumulative error when applied repeatedly over a sequence of calculations f.setRoundingMode(RoundingMode.HALF_EVEN); if (f instanceof DecimalFormat) { DecimalFormat df = (DecimalFormat) f; DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); //set group separator to space instead of comma dfs.setGroupingSeparator('' ''); //set Exponent symbol to minus ''e'' instead of ''E'' if (absv>EXP_UP) { dfs.setExponentSeparator("e+"); //force to display the positive sign in the exponent part } else { dfs.setExponentSeparator("e"); } df.setDecimalFormatSymbols(dfs); //use exponent format if v is out side of [EXP_DOWN,EXP_UP] if (absv<EXP_DOWN || absv>EXP_UP) { df.applyPattern("0."+sharpByPrecision+"E0"); } else { df.applyPattern("#,##0."+sharpByPrecision); } } return f.format(v); } /** * Convert "3.1416e+12" to "<b>3</b>.1416e<b>+12</b>" * It is a html format of a number which highlight the integer and exponent part */ private static String htmlize(String s) { StringBuilder resu = new StringBuilder("<b>"); int p1 = s.indexOf(''.''); if (p1>0) { resu.append(s.substring(0, p1)); resu.append("</b>"); } else { p1 = 0; } int p2 = s.lastIndexOf(''e''); if (p2>0) { resu.append(s.substring(p1, p2)); resu.append("<b>"); resu.append(s.substring(p2, s.length())); resu.append("</b>"); } else { resu.append(s.substring(p1, s.length())); if (p1==0){ resu.append("</b>"); } } return resu.toString(); } }

Nota: Utilicé 2 funciones de la librería GUAVA. Si no usa GUAVA, codifíquelo usted mismo:

/** * Equivalent to Strings.repeat("#", n) of the Guava library: */ private static String createSharp(int n) { StringBuilder sb = new StringBuilder(); for (int i=0;i<n;i++) { sb.append(''#''); } return sb.toString(); }


Mis 2 centavos:

if(n % 1 == 0) { return String.format(Locale.US, "%.0f", n)); } else { return String.format(Locale.US, "%.1f", n)); }


No, no importa.

La pérdida de rendimiento debido a la manipulación de la cadena es cero.

Y aquí está el código para recortar el final después de %f

private static String trimTrailingZeros(String number) { if(!number.contains(".")) { return number; } return number.replaceAll("//.?0*$", ""); }


Por qué no:

if (d % 1.0 != 0) return String.format("%s", d); else return String.format("%.0f",d);

Esto debería funcionar con los valores extremos soportados por Double. Rendimientos:

0.12 12 12.144252 0


Respuesta tardía pero ...

Usted dijo que elige almacenar sus números con el tipo doble . Creo que esta podría ser la raíz del problema porque lo obliga a almacenar enteros en dobles (y por lo tanto perder la información inicial sobre la naturaleza del valor). ¿Qué hay acerca de almacenar sus números en instancias de la clase Number (superclase de Double y Integer) y confiar en el polimorfismo para determinar el formato correcto de cada número?

Sé que puede que no sea aceptable refactorizar una parte completa de su código debido a eso, pero podría producir la salida deseada sin código / conversión / análisis adicional.

Ejemplo:

import java.util.ArrayList; import java.util.List; public class UseMixedNumbers { public static void main(String[] args) { List<Number> listNumbers = new ArrayList<Number>(); listNumbers.add(232); listNumbers.add(0.18); listNumbers.add(1237875192); listNumbers.add(4.58); listNumbers.add(0); listNumbers.add(1.2345); for (Number number : listNumbers) { System.out.println(number); } } }

Producirá la siguiente salida:

232 0.18 1237875192 4.58 0 1.2345


Sé que este es un hilo muy antiguo ... Pero creo que la mejor manera de hacerlo es la siguiente:

public class Test { public static void main(String args[]){ System.out.println(String.format("%s something",new Double(3.456))); System.out.println(String.format("%s something",new Double(3.456234523452))); System.out.println(String.format("%s something",new Double(3.45))); System.out.println(String.format("%s something",new Double(3))); } }

Salida:

3.456 something 3.456234523452 something 3.45 something 3.0 something

El único problema es el último donde no se elimina .0. Pero si eres capaz de vivir con eso, entonces esto funciona mejor. % .2f lo redondeará a los últimos 2 dígitos decimales. También lo hará DecimalFormat. Si necesita todos los lugares decimales pero no los ceros finales, entonces esto funciona mejor.


Si la idea es imprimir enteros almacenados como dobles como si fueran enteros, e imprimir los dobles con la precisión mínima 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 confía en la manipulación de cuerdas.


Tenga en cuenta que String.format(format, args...) depende de la configuración regional, ya que se formatea utilizando la configuración regional predeterminada del usuario, es decir, probablemente con comas e incluso espacios dentro, como 123 456,789 o 123,456.789 , que puede no ser exactamente lo que esperar.

Es posible que prefiera utilizar String.format((Locale)null, format, args...) .

Por ejemplo,

double f = 123456.789d; System.out.println(String.format(Locale.FRANCE,"%f",f)); System.out.println(String.format(Locale.GERMANY,"%f",f)); System.out.println(String.format(Locale.US,"%f",f));

huellas dactilares

123456,789000 123456,789000 123456.789000

y esto es lo que hará String.format(format, args...) en diferentes países.

EDITAR Ok, ya que ha habido una discusión sobre formalidades:

res += stripFpZeroes(String.format((Locale) null, (nDigits!=0 ? "%."+nDigits+"f" : "%f"), value)); ... protected static String stripFpZeroes(String fpnumber) { int n = fpnumber.indexOf(''.''); if (n == -1) { return fpnumber; } if (n < 2) { n = 2; } String s = fpnumber; while (s.length() > n && s.endsWith("0")) { s = s.substring(0, s.length()-1); } return s; }


Utilice un DecimalFormat y setMinimumFractionDigits(0)


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.println o FloatingDecimal.toJavaFormatString usa notaciones científicas si double es menor que 10 ^ -3 o mayor o igual que 10 ^ 7

    double myValue = 0.00000021d; String.format("%s", myvalue); //output: 2.1E-7

  • al utilizar %f , la precisión decimal predeterminada es 6, de lo contrario, puede codificarlo por error, pero se agregan ceros adicionales si tiene menos decimales. Ejemplo:

    double myValue = 0.00000021d; String.format("%.12f", myvalue); //output: 0.000000210000

  • utilizando setMaximumFractionDigits(0); o %.0f elimina cualquier precisión decimal, lo que está bien para los enteros / largos pero no para el doble

    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 usar 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 en INGLÉS asegura que obtenga un punto para el separador decimal, donde sea que se ejecute su programa

¿Por qué usar 340 para setMaximumFractionDigits ?

Dos razones :

  • setMaximumFractionDigits acepta un entero, pero su implementación tiene un máximo de dígitos permitido de DecimalFormat.DOUBLE_FRACTION_DIGITS que es igual a 340
  • Double.MIN_VALUE = 4.9E-324 por lo tanto, con 340 dígitos, está seguro de no redondear su precisión doble y suelta

String s = "1.210000"; while (s.endsWith("0")){ s = (s.substring(0, s.length() - 1)); }

Esto hará que la cadena deje caer los relaves 0-s.


String s = String.valueof("your int variable"); while (g.endsWith("0") && g.contains(".")) { g = g.substring(0, g.length() - 1); if (g.endsWith(".")) { g = g.substring(0, g.length() - 1); } }


String.format("%.2f", value) ;


if (d == Math.floor(d)) { return String.format("%.0f", d); } else { return Double.toString(d); }


new DecimalFormat("#.##").format(1.199); //"1.2"

Como se señaló en los comentarios, esta no es la respuesta correcta a la pregunta original.
Dicho esto, es una forma muy útil de dar formato a los números sin ceros finales innecesarios.


new DecimalFormat("00.#").format(20.236) //out =20.2 new DecimalFormat("00.#").format(2.236) //out =02.2

  1. 0 para el número mínimo de dígitos
  2. Renders # dígitos

public static String fmt(double d) { String val = Double.toString(d); String[] valArray = val.split("//."); long valLong = 0; if(valArray.length == 2){ valLong = Long.parseLong(valArray[1]); } if (valLong == 0) return String.format("%d", (long) d); else return String.format("%s", d); }

Tuve que usar esta causa d == (long)d me estaba dando una violación en el informe de sonar