División int: ¿Por qué el resultado de 1/3 == 0?

107

Estaba escribiendo este código:

public static void main(String[] args) {
    double g = 1 / 3;
    System.out.printf("%.2f", g);
}

El resultado es 0. ¿Por qué es esto y cómo resuelvo este problema?

Tofiq
fuente

Respuestas:

147

Los dos operandos (1 y 3) son números enteros, por lo tanto, se utiliza la aritmética de números enteros (división aquí). Declarar la variable de resultado como doble solo provoca una conversión implícita después de la división .

La división de enteros, por supuesto, devuelve el resultado real de la división redondeada hacia cero. Por tanto, el resultado de 0.333...se redondea aquí a 0. (Tenga en cuenta que el procesador en realidad no realiza ningún redondeo, pero aún puede pensarlo de esa manera).

Además, tenga en cuenta que si ambos operandos (números) se dan como flotantes; 3.0 y 1.0, o incluso solo el primero , luego se usa aritmética de punto flotante, lo que le da 0.333....

Noldorin
fuente
33
+1 y siempre se redondea hacia abajo. int i = .99999999establece int en 0. Más específicamente, toma la parte entera y descarta el resto.
Byron Whitlock
37
Redondea "hacia cero", que es "hacia abajo" para valores superiores a cero. (+0.9 se redondea a 0, -0.9 también se redondea a 0.)
Adrian Smith
@Byron: Sí, exactamente. No creo que el procesador realmente haga ningún redondeo, ya que la división se implementa de manera muy diferente, pero es útil pensarlo de esa manera.
Noldorin
15
No, sin redondeo: Truncamiento
Basil Bourque
3
@BasilBourque En terminología java, el redondeoDOWN es hacia cero. El redondeo FLOORes hacia el infinito negativo.
Andreas
23

1/3 usa la división de enteros ya que ambos lados son enteros.

Necesitas que al menos uno de ellos sea floato double.

Si está ingresando los valores en el código fuente como su pregunta, puede hacerlo 1.0/3; el 1.0es un doble.

Si obtiene los valores de otro lugar, puede usarlos (double)para convertir el archivo inten un double.

int x = ...;
int y = ...;
double value = ((double) x) / y;
Adrian Smith
fuente
10

Echarlo explícitamente como un double

double g = 1.0/3.0

Esto sucede porque Java usa la operación de división de enteros para 1y 3desde que los ingresó como constantes enteras.

Charlie
fuente
2

Deberías usar

double g=1.0/3;

o

double g=1/3.0;

La división de enteros devuelve un entero.


fuente
2

Porque estás haciendo una división de enteros.

Como dice @Noldorin, si ambos operadores son enteros, entonces se usa la división de enteros.

El resultado 0.33333333 no se puede representar como un número entero, por lo tanto, solo se asigna la parte entera (0) al resultado.

Si alguno de los operadores es double/ float, entonces se llevará a cabo la aritmética de punto flotante. Pero tendrás el mismo problema si haces eso:

int n = 1.0 / 3.0;
Tom
fuente
1

Porque trata 1 y 3 como números enteros, por lo tanto, redondea el resultado a 0, de modo que sea un número entero.

Para obtener el resultado que está buscando, dígale explícitamente a Java que los números son dobles así:

double g = 1.0/3.0;
DanielGibbs
fuente
1

Hacer el 1 se utilizará una división de flotador y flotador

public static void main(String d[]){
    double g=1f/3;
    System.out.printf("%.2f",g);
}
sblundy
fuente
1

La conversión en JAVA es bastante simple pero necesita algo de comprensión. Como se explica en el JLS para operaciones con números enteros :

Si un operador entero que no sea un operador de turno tiene al menos un operando de tipo long, entonces la operación se lleva a cabo con precisión de 64 bits y el resultado del operador numérico es de tipo long. Si el otro operando no es largo, primero se amplía (§5.1.5) para escribir largo mediante promoción numérica (§5.6).

Y un ejemplo es siempre la mejor manera de traducir el JLS;)

int + long -> long
int(1) + long(2) + int(3) -> long(1+2) + long(3)

En caso contrario, la operación se realiza con precisión de 32 bits y el resultado del operador numérico es de tipo int. Si alguno de los operandos no es un int, primero se amplía para escribir int mediante promoción numérica.

short + int -> int + int -> int

Un pequeño ejemplo que usa Eclipse para mostrar que incluso una adición de dos shorts no será tan fácil:

short s = 1;
s = s + s; <- Compiling error

//possible loss of precision
//  required: short
//  found:    int

Esto requerirá una fundición con una posible pérdida de precisión.

Lo mismo es cierto para los operadores de punto flotante.

Si al menos uno de los operandos de un operador numérico es de tipo double, entonces la operación se realiza usando aritmética de coma flotante de 64 bits y el resultado del operador numérico es un valor de tipo double. Si el otro operando no es un doble, primero se amplía (§5.1.5) para escribir doble mediante promoción numérica (§5.6).

Entonces la promoción se hace en el flotador al doble.

Y la combinación de valores enteros y flotantes da como resultado valores flotantes como se dijo

Si al menos uno de los operandos de un operador binario es de tipo de coma flotante, entonces la operación es una operación de coma flotante, incluso si el otro es integral.

Esto es cierto para los operadores binarios, pero no para los "Operadores de asignación" como +=

Un simple ejemplo de trabajo es suficiente para probar esto.

int i = 1;
i += 1.5f;

La razón es que hay un reparto implícito hecho aquí, esto se ejecutará como

i = (int) i + 1.5f
i = (int) 2.5f
i = 2
AxelH
fuente
1

1 y 3 son contantes enteros, por lo que Java hace una división de enteros cuyo resultado es 0. Si desea escribir constantes dobles, debe escribir 1.0y 3.0.

Reiniciar
fuente
1

La solución más sencilla es simplemente hacer esto

double g = ((double) 1 / 3);

Lo que hace esto, ya que no ingresó 1.0 / 3.0, es permitirle convertirlo manualmente al tipo de datos double ya que Java asumió que era una división de enteros, y lo haría incluso si significara reducir la conversión. Esto es lo que se llama operador de conversión.

Ramzi El-Jabali
fuente
1

Hice esto.

double g = 1.0/3.0;
System.out.printf("%gf", g);

Use .0 mientras hace cálculos dobles o de lo contrario Java asumirá que está usando Integers. Si un cálculo usa cualquier cantidad de valores dobles, entonces la salida será un valor doble. Si son todos enteros, la salida será un entero.

BendedWills
fuente
0

(1/3) significa división de números enteros, por eso no puede obtener un valor decimal de esta división. Para resolver este problema utilice:

public static void main(String[] args) {
        double g = 1.0 / 3;
        System.out.printf("%.2f", g);
    }
Maruf Hossain
fuente
0
public static void main(String[] args) {
    double g = 1 / 3;
    System.out.printf("%.2f", g);
}

Dado que tanto 1 como 3 son números enteros, el resultado no se redondea sino que se trunca. Entonces ignoras las fracciones y solo tomas enteros.

Para evitar esto, tenga al menos uno de sus números 1 o 3 como forma decimal 1.0 y / o 3.0.

Bek
fuente
0

Probar esto:

public static void main(String[] args) {
    double a = 1.0;
    double b = 3.0;
    double g = a / b;
    System.out.printf(""+ g);
}
Virus Neeraj
fuente
No publique respuestas de solo código, incluya una explicación de lo que hace su código y cómo (y por qué) resuelve el problema de la pregunta. También considere que esta es una pregunta de hace 8 años que tiene respuestas con votos positivos existentes, y si su respuesta agrega algún valor sobre las respuestas existentes.
Mark Rotteveel
-1

Haga "doble g = 1.0 / 3.0;" en lugar.

Brian Knoblauch
fuente
Solo curiosidad ... ¿qué hay de malo en esta respuesta? Usé este enfoque cuando encontré el problema por primera vez. Se agradecería una explicación de lo que está mal con esta solución. Gracias por adelantado.
Mr.Port St Joe
@ Mr.PortStJoe No proporciona ningún detalle a la persona que hace la pregunta. Al observar la respuesta mejor calificada, podemos ver que también explicaron POR QUÉ está sucediendo. Si bien la respuesta puede ser técnicamente correcta, su utilidad puede considerarse limitada.
Andrew T Finnell
-1

Muchos otros no han logrado señalar el problema real:

Una operación solo con números enteros convierte el resultado de la operación en un número entero.

Esto necesariamente significa que los resultados de coma flotante, que podrían mostrarse como un número entero, se truncarán (recortar la parte decimal).

Que es casting (encasillado / conversión de tipo)?

Varía según la implementación del lenguaje, pero Wikipedia tiene una visión bastante completa y habla de coerción. , que es una pieza fundamental de información para responder a su pregunta.

http://en.wikipedia.org/wiki/Type_conversion

sova
fuente
Esta respuesta es errónea. No hay conversión de tipo o conversión de tipo involucrado en una devisión de enteros como 1/2, no en el idioma de destino (java). Simplemente invoca una división de enteros, que dará como resultado un resultado entero. La conversión de tipos se debe únicamente a la conversión ascendente de inta a doubledurante la asignación.
YoYo
@YoYo ¿Estás diciendo que 0.5 es un número entero? No lo creo, amigo.
sova
1
este colega no dijo nada al respecto 0.5. Simplemente, en Java, 1/2es una división de enteros, lo que resulta en un entero cero. Puede asignar un cero a un doble, seguirá siendo un cero, aunque sea un 0.0doble.
YoYo