División entera: ¿cómo se produce un doble?

249

Para este bloque de código:

int num = 5;
int denom = 7;
double d = num / denom;

El valor de des 0.0. Se puede forzar a trabajar al lanzar:

double d = ((double) num) / denom;

Pero, ¿hay otra forma de obtener el doubleresultado correcto ? No me gusta lanzar primitivas, quién sabe qué puede pasar.

walnutmon
fuente
99
lanzar un 'int' a un doble es seguro, siempre obtendrá el mismo valor sin pérdida de precisión.
Peter Lawrey
1
Me gustaría saber si los siguientes son los pasos correctos tomados por el compilador para la división: 1) emitir num para flotar 2) emitir denom para flotar también 2) dividir num por denom. Avísame si soy incorrecto.
mannyee

Respuestas:

156
double num = 5;

Eso evita un yeso. Pero encontrará que las conversiones de conversión están bien definidas. No tienes que adivinar, solo revisa el JLS . int a double es una conversión cada vez mayor. De §5.1.2 :

Las conversiones primitivas de ampliación no pierden información sobre la magnitud general de un valor numérico.

[...]

La conversión de un valor int o largo a flotante, o de un valor largo a doble, puede dar como resultado una pérdida de precisión, es decir, el resultado puede perder algunos de los bits menos significativos del valor. En este caso, el valor de punto flotante resultante será una versión correctamente redondeada del valor entero, utilizando el modo redondeado al más cercano IEEE 754 (§4.2.4) .

5 se puede expresar exactamente como un doble.

Matthew Flaschen
fuente
6060
+1. Deja de tener miedo al casting. Aprende cómo funciona. Todo está bien definido.
Mark Peters
1
@FabricioPH Esto funciona en todas las situaciones, e idénticamente a la solución * 1.0.
Vitruvio
3
@Saposhiente Va más allá de trabajar o no. Cambiar el tipo de una variable me parece un código sucio. Si tiene algo que DEBE SER un número entero y cambia la representación de un flotador solo para poder realizar la operación matemática, puede estar arriesgándose. También en algún contexto, leer la variable como un entero hace que el código sea más fácil de entender.
Fabricio PH
2
@FabricioPH, multiplicar por 1.0todavía cambia el tipo de resultado, simplemente de una manera diferente. 'Me parece un código sucio' no explica en qué escenario (s) cree que multiplicar 1.0es realmente mejor (o por qué podría ser).
Matthew Flaschen
44
@FabricioPH Usted y el OP parecen estar trabajando bajo la falsa creencia (donde dice "Cambiar el tipo de la variable") que hacer de (double)numalguna manera cambia num. No lo hace: crea un doble temporal para el contexto de la declaración.
Paul Tomblin
100

¿Qué hay de malo en lanzar primitivas?

Si no quieres emitir por alguna razón, puedes hacer

double d = num * 1.0 / denom;
Paul Tomblin
fuente
63
... que hace un lanzamiento implícito antes de la multiplicación
Alice Purcell
2
En la mayoría de los casos, esto es mejor que cambiar el tipo de otra variable.
Fabricio PH
3
@FabricioPH Nada sugiere que esto sea cierto, a menos que tenga una fuente para citar.
Vitruvio
1
@Saposhiente respondió en su otro comentario similar
Fabricio PH
1
También puede usar el postfix "D" (para realizar la misma conversión implícita); - Así, por ejemplo:double d = num * 1D / denom;
BrainSlugs83
73

No me gusta lanzar primitivas, quién sabe qué puede pasar.

¿Por qué tienes un miedo irracional a lanzar primitivas? Nada malo sucederá cuando lanzas un inta double. Si no está seguro de cómo funciona, búsquelo en la Especificación del lenguaje Java . Lanzar un intto doublees una conversión primitiva cada vez mayor .

Puedes deshacerte del par de paréntesis extra al usar el denominador en lugar del numerador:

double d = num / (double) denom;
Jesper
fuente
2
usted también puede hacer double d = (double) num / denom;... (OK, esto depende de la precedencia)
user85421
27

Si cambia el tipo de una de las variables, debe recordar colarse en un doble nuevamente si su fórmula cambia, porque si esta variable deja de ser parte del cálculo, el resultado es confuso. Tengo la costumbre de emitir dentro del cálculo y agrego un comentario al lado.

double d = 5 / (double) 20; //cast to double, to do floating point calculations

Tenga en cuenta que emitir el resultado no lo hará

double d = (double)(5 / 20); //produces 0.0
alianos
fuente
17

Emite uno de los enteros / ambos enteros para flotar para forzar que la operación se haga con coma flotante matemática. De lo contrario, siempre se prefiere la matemática entera. Entonces:

1. double d = (double)5 / 20;
2. double v = (double)5 / (double) 20;
3. double v = 5 / (double) 20;

Tenga en cuenta que emitir el resultado no lo hará. Porque la primera división se realiza según la regla de precedencia.

double d = (double)(5 / 20); //produces 0.0

No creo que haya ningún problema con el casting como tal en el que está pensando.

Nikhil Kumar
fuente
10

La fundición de tipos es la única forma


Producir una doubledivisión de enteros: no hay otra forma sin lanzar (puede que no lo hagas explícitamente, pero sucederá).

Ahora, hay varias formas en que podemos tratar de conseguir precisa doublede valor (donde numy denomson inttipo y de curso con la fundición ) -

  1. con casting explícito:

    • double d = (double) num / denom;
    • double d = ((double) num) / denom;
    • double d = num / (double) denom;
    • double d = (double) num / (double) denom;

pero no double d = (double) (num / denom);

  1. con casting implícito:

    • double d = num * 1.0 / denom;
    • double d = num / 1d / denom;
    • double d = ( num + 0.0 ) / denom;
    • double d = num; d /= denom;

pero no double d = num / denom * 1.0;
y nodouble d = 0.0 + ( num / denom );

Minhas Kamal
fuente
2

usa algo como:

double step = 1d / 5;

(1d es un elenco para duplicar)

ungalcrys
fuente
55
1d no es un elenco, es solo una declaración.
Sefier Tang
0

Puede considerar ajustar las operaciones. Por ejemplo:

class Utils
{
    public static double divide(int num, int denom) {
        return ((double) num) / denom;
    }
}

Esto le permite buscar (solo una vez) si el elenco hace exactamente lo que quiere. Este método también podría estar sujeto a pruebas, para garantizar que continúe haciendo lo que desea. Tampoco importa qué truco use para causar la división (podría usar cualquiera de las respuestas aquí), siempre que resulte en el resultado correcto. En cualquier lugar donde necesite dividir dos enteros, ahora puede llamar Utils::dividey confiar en que hace lo correcto.

Ken Wayne VanderLinde
fuente
0

solo usa esto.

int fxd=1;
double percent= (double)(fxd*40)/100;
Mabood Ahmad
fuente
0

La mejor manera de hacer esto es

int i = 3;
Double d = i * 1.0;

d is 3.0 now.
Alp Altunel
fuente