Como converter um duplo para longo sem vazamento?


191

Qual é a melhor maneira de converter um dobro para um longo sem vazamento?

Por exemplo:

double d = 394.000;
long l = (new Double(d)).longValue();
System.out.println("double=" + d + ", long=" + l);

2
apenas certifique-se você não operar com duplas mais de 2 ^ 54 ou números não se encaixam na fração , por isso, por exemplo, expressões como myLong == (long)(myDouble + 1)onde myLongiguais myDoubleirá avaliar atrue
Vitalii Fedorenko

Este método ( Double.longValue();) ainda é útil se você tiver valores duplos de coisas como uma lista de matrizes como essa, ArrayList<Double>pois você receberá um erro que não pode ser convertido. Só estou dizendo isso para quem veio aqui e teve um problema um pouco diferente.
SARose

Respostas:


250

Supondo que você esteja feliz com o truncamento em direção a zero, basta transmitir:

double d = 1234.56;
long x = (long) d; // x = 1234

Isso será mais rápido do que passar pelas classes de wrapper - e, mais importante, é mais legível. Agora, se você precisar de arredondamentos diferentes de "sempre para zero", precisará de um código um pouco mais complicado.


8
Ótima resposta - a parte em direção ao zero teria sido errada para o meu aplicativo, então aplausos por destacar isso na sua resposta e lembrar meu cérebro de ressaca de usar Math.round () aqui em vez de apenas transmitir!
Phantomwhale

123

... E aqui está o caminho arredondado que não trunca. Apressou-se a procurá-lo no Java API Manual:

double d = 1234.56;
long x = Math.round(d); //1235

Não dá o mesmo resultado que um elenco. Então, depende do que o rico quer fazer.
Cyrille Ka

3
sim. pensava-se como um complemento ao que Jon disse :)
Johannes Schaub - litb

2
Eu gosto disso, pois também funciona com objetos Double e Long, em vez de tipos primitivos.
Themanatuf

58

A abordagem preferida deve ser:

Double.valueOf(d).longValue()

Na documentação Double (Java Platform SE 7) :

Double.valueOf(d)

Retorna uma Doubleinstância que representa o doublevalor especificado . Se uma nova Doubleinstância não for necessária, esse método geralmente deve ser usado preferencialmente ao construtor Double(double), pois esse método provavelmente produzirá um desempenho de espaço e tempo significativamente melhor armazenando em cache os valores solicitados frequentemente.


36

(new Double(d)).longValue() internamente apenas faz um cast, portanto não há razão para criar um objeto Double.


13

A biblioteca Guava Math possui um método especialmente projetado para converter um duplo em um longo:

long DoubleMath.roundToLong(double x, RoundingMode mode)

Você pode usar java.math.RoundingModepara especificar o comportamento de arredondamento.


7

Se você tem uma forte suspeita de que o DUPLO é realmente LONGO, e deseja

1) identifique seu valor EXATO como LONGO

2) lançar um erro quando não for LONGO

você pode tentar algo como isto:

public class NumberUtils {

    /**
    * Convert a {@link Double} to a {@link Long}.
    * Method is for {@link Double}s that are actually {@link Long}s and we just
    * want to get a handle on it as one.
    */
    public static long getDoubleAsLong(double specifiedNumber) {
        Assert.isTrue(NumberUtils.isWhole(specifiedNumber));
        Assert.isTrue(specifiedNumber <= Long.MAX_VALUE && specifiedNumber >= Long.MIN_VALUE);
        // we already know its whole and in the Long range
        return Double.valueOf(specifiedNumber).longValue();
    }

    public static boolean isWhole(double specifiedNumber) {
        // http://stackoverflow.com/questions/15963895/how-to-check-if-a-double-value-has-no-decimal-part
        return (specifiedNumber % 1 == 0);
    }
}

Long é um subconjunto de Double; portanto, você pode obter resultados estranhos se tentar converter um Double fora do intervalo de Long:

@Test
public void test() throws Exception {
    // Confirm that LONG is a subset of DOUBLE, so numbers outside of the range can be problematic
    Assert.isTrue(Long.MAX_VALUE < Double.MAX_VALUE);
    Assert.isTrue(Long.MIN_VALUE > -Double.MAX_VALUE); // Not Double.MIN_VALUE => read the Javadocs, Double.MIN_VALUE is the smallest POSITIVE double, not the bottom of the range of values that Double can possible be

    // Double.longValue() failure due to being out of range => results are the same even though I minus ten
    System.out.println("Double.valueOf(Double.MAX_VALUE).longValue(): " + Double.valueOf(Double.MAX_VALUE).longValue());
    System.out.println("Double.valueOf(Double.MAX_VALUE - 10).longValue(): " + Double.valueOf(Double.MAX_VALUE - 10).longValue());

    // casting failure due to being out of range => results are the same even though I minus ten
    System.out.println("(long) Double.valueOf(Double.MAX_VALUE): " + (long) Double.valueOf(Double.MAX_VALUE).doubleValue());
    System.out.println("(long) Double.valueOf(Double.MAX_VALUE - 10).longValue(): " + (long) Double.valueOf(Double.MAX_VALUE - 10).doubleValue());
}

Long is a subset of Doublenão é preciso. O número de dígitos significativos para Long é maior que Double, portanto, algumas informações mantidas por Long podem ser perdidas quando convertidas em Double. Exemplo = tio.run/…
Thariq Nugrohotomo 15/11

4

Deseja ter uma conversão binária como

double result = Double.longBitsToDouble(394.000d);

2
É o oposto do que está sendo perguntado.
Lucas Phillips

@LucasPhillips Você está certo. Devo ter interpretado mal a pergunta, mas deixarei minha resposta, pois ela pode ajudar outras pessoas.
pvorb

1

Simplesmente pelo seguinte:

double d = 394.000;
long l = d * 1L;

0

Simplificando, a conversão é mais eficiente do que criar um objeto Duplo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.