2010-10-26 26 views
13

¿Cuál es la secuencia correcta de las operaciones matemáticas en esta expresión en Java:¿Cuál es la prioridad derecha de la expresión matemática

a + b * c/(d - e) 
1. 4 1 3  2 
2. 4 2 3  1 

entiendo que resultado es el mismo en ambas respuestas. Pero me gustaría entender completamente la lógica del compilador de Java. ¿Qué se ejecuta primero en este ejemplo: la multiplicación o la expresión entre paréntesis? Un enlace a la documentación que cubre que sería útil.

ACTUALIZACIÓN: Gracias a todos por las respuestas. La mayoría de ustedes escribe que la expresión entre paréntesis se evalúa primero. Después de mirar las referencias proporcionadas por Grodriguez creé pequeñas pruebas:

int i = 2; 
System.out.println(i * (i=3)); // prints '6' 
int j = 2; 
System.out.println((j=3) * j); // prints '9' 

Podrían explicar a nadie por qué estas pruebas producen resultados diferentes? Si se evalúa la expresión entre paréntesis, primero esperaría el mismo resultado: 9.

+1

Ninguna de estas respuestas responde a su pregunta porque pregunta por el paréntesis; no están incluidos en la documentación de precedencia. Cabe señalar que esto se realiza mejor de esta manera: ¿se evalúan primero las expresiones entre paréntesis o se evalúan cuando es necesario? Si se evalúa primero, (2) sería correcto ... si se evalúa cuando es necesario (flojo), entonces (1) sería correcto. No sé la respuesta, pero quizás esto sea de ayuda para ti. –

+0

@Myrddin: tienes razón. Eso fue lo que quise hacer la pregunta. – bancer

+0

"Evaluar el operando de la mano izquierda primero". C.f. mi respuesta editada –

Respuesta

10

Casi todo el mundo ha confundido el orden de evaluación con la precedencia del operador. En Java las reglas de prioridad hacen la expresión equivalente a la siguiente:

a + (b * c)/(d - e) 

porque * y / tienen la misma prioridad y se dejan asociativo.

El orden de evaluación se define estrictamente como left hand operand first, then right, then operation (excepto para || y & &). Por lo que el orden de evaluación es:

a 
     b 
     c 
    * 
     d 
     e 
    - 
/
+ 

orden de evaluación baja la página. La sangría refleja la estructura del árbol de sintaxis

Editar

En respuesta a los comentarios de Grodriguez.El programa siguiente:

public class Precedence 
{ 
    private static int a() 
    { 
     System.out.println("a"); 
     return 1; 
    } 
    private static int b() 
    { 
     System.out.println("b"); 
     return 2; 
    } 
    private static int c() 
    { 
     System.out.println("c"); 
     return 3; 
    } 
    private static int d() 
    { 
     System.out.println("d"); 
     return 4; 
    } 
    private static int e() 
    { 
     System.out.println("e"); 
     return 5; 
    } 

    public static void main(String[] args) 
    { 
     int x = a() + b() * c()/(d() - e()); 
     System.out.println(x); 
    } 
} 

produce la salida

a 
b 
c 
d 
e 
-5 

que muestra claramente la multiplicación se lleva a cabo antes de la resta.

+1

"Las implementaciones del lenguaje de programación Java deben respetar el orden de evaluación como se indica explícitamente entre paréntesis e implícitamente por la precedencia del operador". (JLS, 15.7.3) – Grodriguez

+0

@Grodriguez: "El operando de la izquierda de un operador binario parece estar completamente evaluado antes * de que se evalúe cualquier parte * del operando de la derecha". (JLS 15.7.1). [énfasis mío] El orden de evaluación en mi ejemplo cumple completamente con 15.7.3. – JeremyP

+1

@JeremyP Wow, escribí exactamente el mismo programa para demostrarme que estaba en lo cierto. – ILMTitan

12

Como JeremyP tiene muy bien shown us, la primera respuesta es correcta.

En general, se aplican las siguientes reglas:

  • Cada operando de un operador se evalúa antes de que se realiza la operación en sí (excepto para ||, &&, y ?:)
  • operandos son evaluados de izquierda a derecho. El operando de la izquierda de un operador binario parece estar completamente evaluado antes de que se evalúe cualquier parte del operando de la derecha.
  • el orden de evaluación respeta paréntesis y la precedencia de operadores:
    • Los paréntesis se evalúan primero.
    • Los operadores se evalúan por orden de precedencia.
    • Los operadores con igual precedencia se evalúan de izquierda a derecha, excepto los operadores de asignación que se evalúan de derecha a izquierda.

Tenga en cuenta que las dos primeras reglas explican el resultado en su segunda pregunta:

int i = 2; 
System.out.println(i * (i=3)); // prints '6' 
int j = 2; 
System.out.println((j=3) * j); // prints '9' 

Documentación de referencia:

http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4779

Tutorial:

http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

+0

+1 para el primer enlace – bancer

+0

Esta descripción es correcta en términos del resultado generado para la expresión, pero no siempre es cierto decir "los paréntesis se evalúan primero". Si alguna de las cosas entre paréntesis son métodos, entonces esto podría ser significativo. – DJClayworth

+1

La segunda respuesta no es correcta. '*' y '/' tienen igual precendencia y se dejan asociativos. La expresión es por lo tanto equivalente a 'a + ((b * c)/(d - e))'. Junto con la regla de que los operandos izquierdos se evalúan primero, significa que 'b * c' se evalúa primero. – JeremyP

0

estoy asumiendo que su expresión sería algo así como

x = a + b * c/(D - E)

el operador de igualdad tiene derecho a fin izquierdo de la evaluación. entonces la expresión a la derecha de = se evaluará primero.

si su refieren este gráfico precedencia: http://www.java-tips.org/java-se-tips/java.lang/what-is-java-operator-precedence.html

1) serán evaluados los soportes (de), digamos (de) = f por lo que la expresión se convierte entonces en x = a + b * c/F.

2) Ahora * y/tienen la misma precedencia, pero el orden de evaluación es de izquierda a derecha para * se evaluará primero así que digamos b * c = g, entonces la expresión se convierte en x = a + g/f

3) Ahora/tiene la siguiente prioridad tan g/f será evaluado a digamos h por lo que la expresión se procederá x = a + h,

4) evaluar, por último, a + h

+0

* el operador de igualdad *? Quiere decir * el operador de asignación *. –

-1

el los resultados del cálculo están definidos por el Operator Order of Precedence. Entonces, los paréntesis tienen la precedencia más alta aquí, la multiplicación y la división son las más altas, y la suma y la resta más bajas. Los operadores con la misma precedencia se evalúan de izquierda a derecha. Así, la expresión de la pregunta es equivalente a:

a + (b * c)/(d - e)) 

Sin embargo, existe una pequeña diferencia entre lo que normalmente se entiende por "ser evaluado primero" y la prioridad de los operadores para obtener la respuesta correcta.

"d-e" no necesariamente se calcula realmente antes de calcular "a". Esto prácticamente no hace ninguna diferencia a menos que una de las "variables" en la expresión sea realmente una función. The Java standard does not specify the order of evaluation of components of an expression.

+2

El texto de su enlace parece estar en contradicción con el texto al que se vincula. Solo incluye una guía de estilo que indica que confiar demasiado puede causar un código confuso. – ILMTitan

-1
a + b * c/(d - e) 
     1   1 
      2 
    3 

El punto de prioridad de los operadores es convertir la expresión en un árbol sintáctico. Aquí, el * y el - se encuentran en el mismo nivel del árbol. Cuál se evalúa primero es irrelevante para el resultado y no está garantizado .

Editar: Lo siento, me confundí mi fondo de C. Como han señalado otros, Java tiene una regla de "evaluar el funcionamiento de la mano izquierda primero". Al aplicar esta regla al /, se le informa que * se evalúa primero (su primera respuesta).

+0

¿* y/o no tienen el mismo nivel de precedencia? ¿Hay alguna razón para creer que hará la multiplicación antes de la división o simplemente porque de izquierda a derecha pone el * antes de que el/ – Chris

+0

Java se aplique de izquierda a derecha para los operadores con la misma precedencia? – Grodriguez

+0

De la [Especificación de Java] (http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#239829): "[*,/y%] tienen la misma precedencia y son sintácticamente asociativos de izquierda (se agrupan de izquierda a derecha) ". –

4

Evalúa las expresiones en el siguiente orden. Los nombres de variables son expresiones que deben ser evaluadas.

a + b * c/(d - e) 
    2 3 5 6 
     4  7 
1   8 
    9 

Entonces, la respuesta a su pregunta es # 1. El orden de las operaciones determina la forma del árbol de expresiones (cuál es el lado izquierdo del árbol y cuál es el correcto), pero el lado izquierdo siempre se evalúa primero (y la raíz se evalúa en último lugar).

+0

+1 para verificar la respuesta en contra de la realidad :) – JeremyP

0

En su segunda pregunta, parece que Java está evaluando la parte entre paréntesis como una tarea, no como una expresión matemática. Esto significa que no realizará asignaciones entre paréntesis en el mismo orden que las operaciones entre paréntesis.

+1

Asignaciones ** son ** expresiones! –

1

Me imagino que podría evaluar algo como esto evaluando de izquierda a derecha.

a + b * c/(d-e)

Action   Left Value  Right Value 
Start Add  a    b*c/(d-e) 
Start Multiply b    c 
Calc Multiply (since it can)  
Start Divide  b*c    (d-e) 
Start Subtract d    e 
Calc Subtract 
Calc Divide 
Calc Add 

Esto puede ser pensado como la creación de un árbol binario que representa los cálculos y luego trabajar desde los nodos hoja, de izquierda a derecha, el cálculo de las cosas. Por desgracia mi arte ASCII no es muy grande pero aquí hay un intento de representar el árbol en cuestión:

Add 
    /\ 
/\ 
    a \ 
    Divide 
    /\ 
    / \ 
    / \ 
    /  \ 
Multiply Subtract 
    /\   /\ 
/\  /\ 
b c  d e 

Y me hizo algunas pruebas en C# (Sé que no es el mismo, pero ahí es donde mis intereses se encuentran y las pruebas pueden ser fácilmente adaptado) como sigue:

 f = 1; 
     Console.WriteLine((f=2) + (f) * (f)/((f) - (f)-1)); 
     Console.WriteLine(2 + 2 * 2/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f=2) * (f)/((f) - (f)-1)); 
     Console.WriteLine(1 + 2 * 2/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f) * (f = 2)/((f) - (f)-1)); 
     Console.WriteLine(1 + 1 * 2/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f) * (f)/((f=2) - (f)-1)); 
     Console.WriteLine(1 + 1 * 1/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f) * (f)/((f) - (f=2)-1)); 
     Console.WriteLine(1d + 1d * 1d/(1d - 2d - 1d)); 

los pares de estados Console.WriteLine son el uno algebraica (utilizando el conjunto de un número truco) y una representación numérica que muestra lo que realmente hace el cálculo. Los pares producen el mismo resultado que el otro.

Como se puede ver, los argumentos se evalúan en orden con cualquiera después de que la asignación sea 2 y los anteriores sean uno. Entonces, el orden de evaluación de las cosas es simple, de izquierda a derecha, pero el orden de los cálculos es el que cabría esperar.

Asumo que esto puede funcionar casi con copiar y pegar para poner a prueba en JAVA ...

Puede haber algunos supuestos inadvertido en aquí así que si alguien hace defectos lógicos en lugar aquí, por favor llámeme en ellos y Los resolveré.

+0

Su árbol está equivocado. Multiplicar debe ser el lado izquierdo en Divide. Pruebe el caso donde b = 20, c = 1, d = 20 y e = 0. – ILMTitan

+0

No, Chris, es 'a + (b * c)/(d-e)', no 'a + b * (c/(d-e))'. Porque *,/y% tienen asociatividad a la izquierda. –

+0

ILMTitan: presumiblemente esos números y usando enteros para que la c/(d-e) se trunque a cero mostrando la diferencia. No lo probé en el código, pero veo cómo funcionaría. :) Edgar Bonet: OK, sí. Veo a que te refieres. Realmente no había comprobado lo suficiente parece. Está parado para razonar que hay una regla. :) Actualizaré mi increíble ascii art ... ;-) – Chris

Cuestiones relacionadas