¿Cómo imprimo un valor doble sin notación científica usando Java?


222

Quiero imprimir un valor doble en Java sin forma exponencial.

double dexp = 12345678;
System.out.println("dexp: "+dexp);

Muestra esta notación E: 1.2345678E7.

Quiero que lo imprima así: 12345678

¿Cuál es la mejor manera de prevenir esto?

Respuestas:


116

Puedes usar printf()con %f:

double dexp = 12345678;
System.out.printf("dexp: %f\n", dexp);

Esto se imprimirá dexp: 12345678.000000. Si no quieres la parte fraccional, usa

System.out.printf("dexp: %.0f\n", dexp);

Utiliza el lenguaje especificador de formato explicado en la documentación .

El toString()formato predeterminado utilizado en su código original se detalla aquí .


1
pero mostró dexp: 12345681.000000cuál es el valor incorrecto. Y, en realidad, después de eso quiero mostrarlo en mi página web donde se muestra de esta manera 1.2345678E7. ¿Hay 12345678alguna forma de que pueda almacenarlo en cualquier doble y de otra manera?
Despicable el

1
@despicable: es posible que haya estado mirando la versión antigua e incompleta de la respuesta. Intenta volver a cargar la página. Debería haber un párrafo sobre %.0f.
NPE

@despicable, puede almacenar dexp como int para poder usarlo fácilmente en ambos sentidos
Justin

10
REDUCE EL NÚMERO
Confunde el

66
%.0fRedondea el número. ¿Hay alguna forma de descartar los ceros finales?
NurShomik el

239

Java evita la notación E en un doble:

Cinco formas diferentes de convertir un número doble en un número normal:

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Runner {
    public static void main(String[] args) {
        double myvalue = 0.00000021d;

        //Option 1 Print bare double.
        System.out.println(myvalue);

        //Option2, use decimalFormat.
        DecimalFormat df = new DecimalFormat("#");
        df.setMaximumFractionDigits(8);
        System.out.println(df.format(myvalue));

        //Option 3, use printf.
        System.out.printf("%.9f", myvalue);
        System.out.println();

        //Option 4, convert toBigDecimal and ask for toPlainString().
        System.out.print(new BigDecimal(myvalue).toPlainString());
        System.out.println();

        //Option 5, String.format 
        System.out.println(String.format("%.12f", myvalue));
    }
}

Este programa imprime:

2.1E-7
.00000021
0.000000210
0.000000210000000000000001085015324114868562332958390470594167709350585
0.000000210000

Que son todos del mismo valor.

Protip: Si está confundido acerca de por qué esos dígitos aleatorios aparecen más allá de cierto umbral en el valor doble, este video explica: computerphile ¿por qué 0.1+ es 0.2igual 0.30000000000001?

http://youtube.com/watch?v=PZRI1IfStY0


Muchas gracias por la respuesta y especialmente por el consejo. Ese video resolvió mi confusión.
AnujDeo

97

En breve:

Si desea deshacerse de los ceros finales y los problemas de configuración regional, debe usar:

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.printlno FloatingDecimal.toJavaFormatStringutiliza notación científica si doble es menos de 10 ^ -3 o mayor que o igual a 10 ^ 7
  • Al usar %f, la precisión decimal predeterminada es 6, de lo contrario, puede codificarla, pero da como resultado ceros adicionales agregados si tiene menos decimales. Ejemplo:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); // Output: 0.000000210000
  • Al usar setMaximumFractionDigits(0);o %.0feliminar cualquier precisión decimal, lo cual está bien para 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, usted es dependiente local. En el idioma francés, 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 asegura que obtenga un punto para el separador decimal, donde sea que se ejecute su programa.

¿Por qué usar 340 entonces para setMaximumFractionDigits ?

Dos razones:

  • setMaximumFractionDigitsacepta un número entero, pero su implementación tiene un máximo de dígitos permitidos de los DecimalFormat.DOUBLE_FRACTION_DIGITScuales es igual a 340
  • Double.MIN_VALUE = 4.9E-324 así que con 340 dígitos está seguro de no redondear su doble y perder precisión.

¿Cuál es su opinión? new BigDecimal(myvalue).toPlainString()De la descripción en docs.oracle.com/javase/7/docs/api/java/math/… ), no es inmediatamente obvio cómo se comporta cuando se le dan diferentes tipos de números, pero elimina la notación científica .
Derek Mahar

44
new BigDecimal(0.00000021d).toPlainString()salida 0.0000002100000000000000010850153241148685623329583904705941677093505859375que no es lo que esperarías ...
JBE

¿Alguna idea de cómo usar su respuesta en scala? Probablemente sea una cuestión de importaciones apropiadas, pero soy nuevo aquí.
Jangorecki

BigDecimal.valueOf(0.00000021d).toPlainString()funciona bien (usa el constructor de cadenas de BigDecimal por eso)
marco

27

Puedes probarlo con DecimalFormat. Con esta clase eres muy flexible al analizar tus números.
Puede establecer exactamente el patrón que desea usar.
En su caso, por ejemplo:

double test = 12345678;
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(0);
System.out.println(df.format(test)); //12345678

16

Tengo otra solución que involucra a BigDecimal's toPlainString (), pero esta vez usando el constructor de cadenas, que se recomienda en el javadoc:

Este constructor es compatible con los valores devueltos por Float.toString y Double.toString. Esta es generalmente la forma preferida de convertir un flotante o doble en un BigDecimal, ya que no sufre la imprevisibilidad del constructor BigDecimal (doble).

Se ve así en su forma más corta:

return new BigDecimal(myDouble.toString()).stripTrailingZeros().toPlainString();

Antes de Java 8, esto da como resultado "0.0" para cualquier Dobles de valor cero, por lo que deberá agregar:

if (myDouble.doubleValue() == 0)
    return "0";

NaN e infinitos valores tienen que ser verificados extra.

El resultado final de todas estas consideraciones:

public static String doubleToString(Double d) {
    if (d == null)
        return null;
    if (d.isNaN() || d.isInfinite())
        return d.toString();

    // Pre Java 8, a value of 0 would yield "0.0" below
    if (d.doubleValue() == 0)
        return "0";
    return new BigDecimal(d.toString()).stripTrailingZeros().toPlainString();
}

Esto también se puede copiar / pegar para que funcione bien con Float.


2
He leído innumerables esquemas para convertir un valor doble en una Cadena y este es el mejor: corto, directo, configurable.
Paul

Gran solución, realmente me ayudó a convertir valores dobles a String y evitar la notación científica. ¡Gracias!
Pleft

¿Por qué en d.doubleValue() == 0lugar de d == 0?
Alexei Fando

Porque evita el desempaquetado automático, que me gusta más en esa situación, pero las opiniones pueden diferir en esto. Si está en Java 8 (9 probablemente será el mismo), puede omitir esas 2 líneas por completo.
Manuel

Acabo de probar con Java 9, esas 2 líneas también se pueden omitir en 9.
Manuel

8

Esto funcionará siempre que su número sea un número entero:

double dnexp = 12345678;
System.out.println("dexp: " + (long)dexp);

Si la variable doble tiene precisión después del punto decimal, la truncará.


4

Necesitaba convertir algunos valores de doble a moneda y descubrí que la mayoría de las soluciones estaban bien, pero no para mí.

El DecimalFormatfue finalmente el camino para mí, así que aquí es lo que he hecho:

   public String foo(double value) //Got here 6.743240136E7 or something..
    {
        DecimalFormat formatter;

        if(value - (int)value > 0.0)
            formatter = new DecimalFormat("0.00"); // Here you can also deal with rounding if you wish..
        else
            formatter = new DecimalFormat("0");

        return formatter.format(value);
    }

Como puede ver, si el número es natural, obtengo, digamos, 20000000 en lugar de 2E7 (etc.), sin ningún punto decimal.

Y si es decimal, solo obtengo dos dígitos decimales.


4

El compilador Java / Kotlin convierte cualquier valor mayor que 9999999 (mayor o igual a 10 millones) a notación científica, es decir. Notación de Epsilion .

Ej: 12345678 se convierte a 1.2345678E7

Use este código para evitar la conversión automática a notación científica:

fun setTotalSalesValue(String total) {
        var valueWithoutEpsilon = total.toBigDecimal()
        /* Set the converted value to your android text view using setText() function */
        salesTextView.setText( valueWithoutEpsilon.toPlainString() )
    }

3

El siguiente código detecta si el número proporcionado se presenta en notación científica. Si es así, se representa en una presentación normal con un máximo de '25' dígitos.

 static String convertFromScientificNotation(double number) {
    // Check if in scientific notation
    if (String.valueOf(number).toLowerCase().contains("e")) {
        System.out.println("The scientific notation number'"
                + number
                + "' detected, it will be converted to normal representation with 25 maximum fraction digits.");
        NumberFormat formatter = new DecimalFormat();
        formatter.setMaximumFractionDigits(25);
        return formatter.format(number);
    } else
        return String.valueOf(number);
}

2

Creo que todos tuvieron la idea correcta, pero todas las respuestas no fueron sencillas. Puedo ver que este es un código muy útil. Aquí hay un fragmento de lo que funcionará:

System.out.println(String.format("%.8f", EnterYourDoubleVariableHere));

el ".8" es donde establece el número de decimales que le gustaría mostrar.

Estoy usando Eclipse y no funcionó.

Espero que esto haya sido útil. ¡Le agradecería cualquier comentario!


1

Tuve el mismo problema en mi código de producción cuando lo estaba usando como una entrada de cadena para una función matemática. Eval () que toma una cadena como "x + 20/50"

Miré cientos de artículos ... Al final fui con esto debido a la velocidad. Y debido a que la función Eval iba a convertirlo nuevamente en su propio formato de número y math.Eval () no admitía el E-07 final que devolvieron otros métodos, y cualquier cosa por encima de 5 dp era demasiado detalle para mi aplicación de todos modos .

Esto ahora se usa en el código de producción para una aplicación que tiene más de 1,000 usuarios ...

double value = 0.0002111d;
String s = Double.toString(((int)(value * 100000.0d))/100000.0d); // Round to 5 dp

s display as:  0.00021

1

Esto puede ser una tangente ... pero si necesita poner un valor numérico como un entero (que es demasiado grande para ser un entero) en un serializador (JSON, etc.), entonces probablemente desee "BigInterger"

Ejemplo: el valor es una cadena - 7515904334

Necesitamos representarlo como un número en un mensaje Json: {"contact_phone": "800220-3333", "servicer_id": 7515904334, "servicer_name": "ALGUNA CORPORACIÓN"}

No podemos imprimirlo o obtendremos esto: {"contact_phone": "800220-3333", "servicer_id": "7515904334", "servicer_name": "ALGUNA CORPORACIÓN"}

Agregar el valor al nodo de esta manera produce el resultado deseado: BigInteger.valueOf (Long.parseLong (valor, 10))

No estoy seguro de que esto sea realmente sobre el tema, pero dado que esta pregunta fue mi mayor éxito cuando busqué mi solución, pensé que compartiría aquí en beneficio de otros, mentiré, quienes buscan mal. :RE


-1

Para los valores enteros representados por a double, puede usar este código, que es mucho más rápido que las otras soluciones.

public static String doubleToString(final double d) {
    // check for integer, also see https://stackoverflow.com/a/9898613/868941 and
    // https://github.com/google/guava/blob/master/guava/src/com/google/common/math/DoubleMath.java
    if (isMathematicalInteger(d)) {
        return Long.toString((long)d);
    } else {
        // or use any of the solutions provided by others
        return Double.toString(d);
    }
}

// Java 8+
public static boolean isMathematicalInteger(final double d) {
    return StrictMath.rint(d) == d && Double.isFinite(d);
}

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.