Como imprimo um valor duplo sem notação científica usando Java?

222

Quero imprimir um valor duplo em Java sem forma exponencial.

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

Ele mostra esta notação E: 1.2345678E7.

Quero que imprima assim: 12345678

Qual é a melhor maneira de evitar isso?

Desprezível
fonte

Respostas:

116

Você poderia usar printf()com %f:

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

Isso será impresso dexp: 12345678.000000. Se você não deseja a parte fracionária, use

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

Isso usa a linguagem do especificador de formato explicada na documentação .

O toString()formato padrão usado no seu código original está explicitado aqui .

NPE
fonte
1
mas mostrou dexp: 12345681.000000que é errado value.And, na verdade depois então eu quero para exibi-lo na minha página web onde se exibir como este 1.2345678E7.É lá de qualquer maneira pela qual eu posso armazená-lo em qualquer dupla como 12345678e alguma outra maneira?
desprezível
1
@despicable: você pode estar vendo a versão antiga e incompleta da resposta. Tente recarregar a página. Deve haver um parágrafo sobre %.0f.
NPE
@despicable, você pode armazenar o dexp como int, para que você possa usá-lo facilmente nos dois sentidos
Justin
10
TIRA O NÚMERO
Confunda
6
%.0farredonda o número. Existe uma maneira de simplesmente descartar os zeros à direita?
NurShomik
239

A Java evita a notação E em um duplo:

Cinco maneiras diferentes de converter um número duplo para um 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

Quais são todos do mesmo valor.

Protip: se você está confuso sobre o motivo pelo qual esses dígitos aleatórios aparecem além de um certo limite no valor duplo, este vídeo explica: computerphile por que 0.1+0.2 igual a 0.30000000000001?

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

Eric Leschinski
fonte
Muito obrigado pela resposta e principalmente pela dica. Esse vídeo resolveu minha confusão.
AnujDeo 28/02
97

Em resumo:

Se você quiser se livrar dos zeros à direita e dos problemas de localidade, use:

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

Explicação:

Por que outras respostas não me agradaram:

  • Double.toString()ou System.out.printlnou FloatingDecimal.toJavaFormatStringusa notações científicas se o dobro for menor que 10 ^ -3 ou maior que ou igual a 10 ^ 7
  • Ao usar %f, a precisão decimal padrão é 6; caso contrário, você pode codificá-la, mas isso resultará em zeros extras adicionados se você tiver menos casas decimais. Exemplo:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); // Output: 0.000000210000
  • Usando setMaximumFractionDigits(0);ou %.0fvocê remove qualquer precisão decimal, o que é bom para números inteiros / longos, mas não para o dobro:

    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
  • Usando DecimalFormat, você depende localmente. Na localidade francesa, o separador decimal é uma vírgula, não um ponto:

    double myValue = 0.00000021d;
    DecimalFormat df = new DecimalFormat("0");
    df.setMaximumFractionDigits(340);
    System.out.println(df.format(myvalue)); // Output: 0,00000021

    O uso do código do idioma PORTUGUÊS garante que você obtenha um ponto para o separador decimal, onde quer que o seu programa seja executado.

Por que usar 340 então para setMaximumFractionDigits?

Duas razões:

  • setMaximumFractionDigitsaceita um número inteiro, mas sua implementação tem um número máximo permitido dos DecimalFormat.DOUBLE_FRACTION_DIGITSquais é igual a 340
  • Double.MIN_VALUE = 4.9E-324 portanto, com 340 dígitos, você não deve arredondar o dobro e perder a precisão.
JBE
fonte
Qual é a sua opinião new BigDecimal(myvalue).toPlainString()Da descrição em docs.oracle.com/javase/7/docs/api/java/math/… ), não é imediatamente óbvio como ele se comporta quando recebem diferentes tipos de números, mas elimina a notação científica .
Drek Mahar
4
new BigDecimal(0.00000021d).toPlainString()saída 0.0000002100000000000000010850153241148685623329583904705941677093505859375que não é o que você esperaria ...
JBE
alguma idéia de como usar sua resposta no scala? provavelmente uma questão de importações apropriadas, mas sou novo aqui.
Jangorecki
BigDecimal.valueOf(0.00000021d).toPlainString()funciona tão bem (ele usa o construtor String of BigDecimal é por isso)
marco
27

Você pode experimentá-lo DecimalFormat. Com esta classe, você é muito flexível ao analisar seus números.
Você pode definir exatamente o padrão que deseja usar.
No seu caso, por exemplo:

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

Eu tenho outra solução envolvendo o toPlainString () do BigDecimal, mas desta vez usando o construtor String, recomendado no javadoc:

esse construtor é compatível com os valores retornados por Float.toString e Double.toString. Geralmente, é a maneira preferida de converter um float ou duplicar em um BigDecimal, pois não sofre com a imprevisibilidade do construtor BigDecimal (double).

Parece assim em sua forma mais curta:

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

Antes do Java 8, isso resulta em "0,0" para quaisquer duplas com valor zero, portanto, você deve adicionar:

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

NaN e valores infinitos devem ser verificados extra.

O resultado final de todas estas considerações:

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();
}

Isso também pode ser copiado / colado para funcionar bem com o Float.

Manuel
fonte
2
Eu li inúmeros esquemas para converter um valor duplo em uma String e este é o melhor: curto, direto, configurável.
Paul
Ótima solução, realmente me ajudou a converter valores duplos em String e evitar a notação científica. Obrigado!
pleft
Por que ao d.doubleValue() == 0invés de d == 0?
Alexei Fando
Porque evita o desembaraço automático, o que eu mais gosto nessa situação, mas é claro que as visualizações podem diferir nisso. Se você estiver no java 8 (9 provavelmente será o mesmo), poderá deixar de fora essas duas linhas.
Manuel
Apenas experimentado com o java 9, essas duas linhas também podem ser deixadas de fora no 9.
Manuel
8

Isso funcionará desde que seu número seja um número inteiro:

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

Se a variável dupla tiver precisão após o ponto decimal, ela será truncada.

NateS
fonte
4

Eu precisava converter alguns valores duplos em moeda e descobri que a maioria das soluções estava correta, mas não para mim.

A DecimalFormatacabou por ser o caminho para mim, então aqui está o que eu fiz:

   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 você pode ver, se o número for natural, recebo - digamos - 20000000 em vez de 2E7 (etc.) - sem nenhum ponto decimal.

E se for decimal, recebo apenas dois dígitos decimais.

JamesC
fonte
4

O compilador Java / Kotlin converte qualquer valor maior que 9999999 (maior ou igual a 10 milhões) em notação científica, isto é. Notação Epsilion .

Ex: 12345678 é convertido em 1,2345678E7

Use este código para evitar a conversão automática em notação 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() )
    }
Ramakrishna Joshi
fonte
3

O código a seguir detecta se o número fornecido é apresentado em notação científica. Nesse caso, é representado na apresentação normal com um 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);
}
Memin
fonte
1

Acho que todos tiveram a ideia certa, mas todas as respostas não foram diretas. Eu posso ver isso sendo um pedaço de código muito útil. Aqui está um trecho do que irá funcionar:

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

a ".8" é onde você define o número de casas decimais que você gostaria de mostrar.

Estou usando o Eclipse e não funcionou.

Espero que isso tenha sido útil. Eu gostaria de receber qualquer feedback!

Brian Castro
fonte
1

Eu tive esse mesmo problema no meu código de produção quando o estava usando como uma entrada de string para uma função math.Eval () que usa uma string como "x + 20/50"

Eu olhei para centenas de artigos ... No final, eu fui com isso por causa da velocidade. E porque a função Eval iria convertê-lo novamente em seu próprio formato numérico e math.Eval () não suportava o E-07 à direita que outros métodos retornavam, e qualquer coisa acima de 5 dp era muito detalhe para minha aplicação .

Agora isso é usado no código de produção para um aplicativo que possui mais de 1.000 usuários ...

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

s display as:  0.00021
hamish
fonte
1

Isso pode ser uma tangente .... mas se você precisar colocar um valor numérico como um número inteiro (que é muito grande para ser um número inteiro) em um serializador (JSON etc.), provavelmente desejará "BigInterger"

Exemplo: o valor é uma sequência - 7515904334

Precisamos representá-lo como numérico em uma mensagem Json: {"contact_phone": "800220-3333", "servicer_id": 7515904334, "servicer_name": "SOME CORPORATION"}

Não podemos imprimi-lo ou obteremos o seguinte: {"contact_phone": "800220-3333", "servicer_id": "7515904334", "servicer_name": "SOME CORPORATION"}

Adicionar o valor ao nó dessa maneira produz o resultado desejado: BigInteger.valueOf (Long.parseLong (value, 10))

Não tenho certeza se isso é realmente um tópico, mas como essa pergunta foi a minha maior surpresa quando procurei minha solução, pensei em compartilhar aqui para o benefício de outras pessoas, mentir, que pesquisam mal. : D

Keith Fosberg
fonte
-1

Para valores inteiros representados por um double , você pode usar esse código, que é muito mais rápido que as outras soluções.

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);
}
rmuller
fonte
-1

Minha solução: String str = String.format ("% .0f", yourDouble);

Nguyễn Thắng
fonte