¿Cómo convertir un doble a largo sin lanzar?

191

¿Cuál es la mejor manera de convertir un doble en un largo sin lanzar?

Por ejemplo:

double d = 394.000;
long l = (new Double(d)).longValue();
System.out.println("double=" + d + ", long=" + l);
Trineo
fuente
2
solo asegúrese de no operar con dobles más de 2 ^ 54 o los números no encajarán en la fracción , por lo que, por ejemplo, expresiones como myLong == (long)(myDouble + 1)where myLongequals myDoublese evaluarán paratrue
Vitalii Fedorenko
Este método ( Double.longValue();) sigue siendo útil si tiene valores dobles de cosas como una lista de matrices como esta, ArrayList<Double>ya que obtendrá un error de no se puede emitir. Solo digo esto para cualquiera que haya venido y haya tenido un problema ligeramente diferente.
SARose

Respuestas:

250

Asumiendo que estás contento con truncar hacia cero, solo lanza:

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

Esto será más rápido que ir a través de las clases de contenedor y, lo que es más importante, es más legible. Ahora, si necesita un redondeo diferente a "siempre hacia cero", necesitará un código un poco más complicado.

Jon Skeet
fuente
8
Gran respuesta: la parte hacia cero habría estado mal para mi aplicación, ¡así que aplausos por resaltar esto en su respuesta y recordarle a mi cerebro con resaca que use Math.round () aquí en lugar de simplemente lanzar!
Phantomwhale
123

... Y aquí está el redondeo que no se trunca. Se apresuró a buscarlo en el Manual API de Java:

double d = 1234.56;
long x = Math.round(d); //1235
Johannes Schaub - litb
fuente
No da el mismo resultado que un elenco. Entonces depende de lo que los ricos quieran hacer.
Cyrille Ka
3
Si. se pensó como una adición a lo que dijo Jon :)
Johannes Schaub - litb
2
Me gusta esto ya que también funciona con objetos dobles y largos en lugar de tipos primitivos.
themanatuf
58

El enfoque preferido debería ser:

Double.valueOf(d).longValue()

De la documentación de Double (Java Platform SE 7) :

Double.valueOf(d)

Devuelve una Doubleinstancia que representa el doublevalor especificado . Si Doubleno se requiere una nueva instancia, este método generalmente debe usarse con preferencia al constructor Double(double), ya que es probable que este método produzca un rendimiento de espacio y tiempo significativamente mejor al almacenar en caché los valores solicitados con frecuencia.

leogps
fuente
36

(new Double(d)).longValue() internamente solo realiza un lanzamiento, por lo que no hay razón para crear un objeto Doble.

Michael Myers
fuente
13

La biblioteca Guava Math tiene un método especialmente diseñado para convertir un doble en uno largo:

long DoubleMath.roundToLong(double x, RoundingMode mode)

Puede usar java.math.RoundingModepara especificar el comportamiento de redondeo.

Tyler 傲 来 国 主
fuente
7

Si tiene una fuerte sospecha de que el DOBLE es en realidad un LARGO, y desea

1) maneje su valor EXACTO como LARGO

2) arroja un error cuando no es LARGO

puedes probar algo como esto:

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 es un subconjunto de Double, por lo que puede obtener algunos resultados extraños si, sin saberlo, intenta convertir un Double que esté fuera del rango 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
fuente
Long is a subset of DoubleNo es exacto. El número de dígitos significativos para Long es mayor que Double, por lo que parte de la información que posee Long se puede perder cuando se convierte en Double. Ejemplo = tio.run/…
Thariq Nugrohotomo
4

¿Quieres tener una conversión binaria como

double result = Double.longBitsToDouble(394.000d);
pvorb
fuente
2
Esto es lo contrario de lo que se pregunta.
Lucas Phillips
@LucasPhillips Tienes razón. Debo haber leído mal la pregunta, pero dejaré mi respuesta ya que podría ayudar a otros.
pvorb
1

Simplemente por lo siguiente:

double d = 394.000;
long l = d * 1L;
devll
fuente
0

En pocas palabras, la conversión es más eficiente que crear un objeto Doble.

Vijay Dev
fuente