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);
Trenó
fonte
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.

Jon Skeet
fonte
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
Johannes Schaub - litb
fonte
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.

leogps
fonte
36

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

Michael Myers
fonte
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.

Tyler 傲 来 国 主
fonte
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());
}
NS du Toit
fonte
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);
pvorb
fonte
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;
devll
fonte
0

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

Vijay Dev
fonte