tipos programacion prioridad precedencia operadores logicos jerarquia comparacion aritmeticos java precedence operator-precedence

java - programacion - Si el paréntesis tiene mayor prioridad, ¿por qué se resuelve primero el operador de incremento?



prioridad de operadores pdf (5)

Tengo un solo código de línea,

int a = 10; a = ++a * ( ++a + 5);

Mi salida esperada era 12 * (11 + 5) = 192 , pero obtuve 187 . Por mucho que supiera, el operador de incremento inside () se debe resolver primero, entonces ¿por qué se resuelve primero el que está afuera?


Citando del blog de Eric Lippert :

La evaluación de una expresión aritmética está controlada por tres conjuntos de reglas: reglas de precedencia, reglas de asociatividad y reglas de orden.

Las reglas de precedencia describen cómo una expresión sin paréntesis debe ser entre paréntesis cuando la expresión mezcla diferentes tipos de operadores.

Las reglas de asociatividad describen cómo una expresión sin paréntesis debe ser entre paréntesis cuando la expresión tiene un grupo del mismo tipo de operador.

Las reglas de orden de evaluación describen el orden en que se evalúa cada operando en una expresión.

Una mayor precedencia da como resultado la agrupación de operandos con un operador y no significa la evaluación de operandos. Es el orden de evaluación que decide la secuencia de evaluación de las subexpresiones en una expresión.

Actualizar:

Como puedo ver, muchos programadores piensan esa afirmación

a = ++a * ( ++a + 5);

invocará un comportamiento indefinido. Sí, invocará a UB si no hay garantía del orden de evaluación de los operandos de un operador.

Pero esto no es cierto en el contexto del lenguaje de programación Java. Tiene un comportamiento bien definido en Java (así como en C #). La especificación del lenguaje Java establece que:

15.7 Orden de evaluación

El lenguaje de programación Java garantiza que los operandos de los operadores parezcan evaluarse en un orden de evaluación específico, es decir, de izquierda a derecha .

Ejemplo 15.7.1-1. El operando de la mano izquierda se evalúa primero

En el siguiente programa, el operador * tiene un operando de la izquierda que contiene una asignación a una variable y un operando de la derecha que contiene una referencia a la misma variable. El valor producido por la referencia reflejará el hecho de que la asignación ocurrió primero.

class Test1 { public static void main(String[] args) { int i = 2; int j = (i=3) * i; System.out.println(j); } }

Este programa produce la salida:

9

No está permitido que la evaluación del operador * produzca 6 en lugar de 9 .

Pero, aún la especificación de Java establece claramente que no escribir tales códigos:

Se recomienda que el código no se base de manera crucial en esta especificación . El código generalmente es más claro cuando cada expresión contiene como máximo un efecto secundario, como su operación más externa, y cuando el código no depende exactamente de qué excepción surge como consecuencia de la evaluación de expresiones de izquierda a derecha.


De ese fragmento

int a = 10; a = ++a * ( ++a + 5);

A veces, la solución más simple es usar javap para comprender el orden de evaluación:

0: bipush 10 // push 10 onto the stack (stack={10}) 2: istore_1 // store 10 into variable 1 (a = 10, stack={}) 3: iinc 1, 1 // increment local variable 1 by 1 (a = 11, stack={}) 6: iload_1 // push integer in local variable 1 onto the stack (a = 11, stack = {11}) 7: iinc 1, 1 // increment local variable 1 by 1 (a = 12, stack={11}) 10: iload_1 // push integer in local variable 1 onto the stack (a = 12, stack = {12, 11}) 11: iconst_5 // load the int value 5 onto the stack (a = 12, stack = {5, 12, 11}) 12: iadd // add 5 and 12 (a = 12, stack = {17, 11}) 13: imul // multiply 17 and 11 (a = 12, stack = {})

  1. a se incrementa en 1. (línea 3) // a = 11
  2. a se incrementa en 1. (línea 7) // a = 12
  3. agregue 5 a a (línea 12) // a = 17
  4. multiplicar 11 por 17 (línea 13) // a = 187

(10 + 1 + 1 + 5) * 11 = 187


El efecto de los paréntesis es controlar qué valores calculados se utilizan como operandos para operaciones posteriores. Controlan la secuencia en la que las operaciones se realizan solo en la medida en que una operación no puede evaluarse hasta después de que sus operandos hayan sido evaluados. Considere las expresiones:

(a()+b()) * (c()+d()) a() + (b()*c()) + d()

El paréntesis no necesita (y en Java no puede) afectar el orden en el que se llama a (), b (), c () y d (). Pueden afectar si la multiplicación se realiza antes o después de que se llame a d (), pero solo en circunstancias muy raras (por ejemplo, d () llamando a una Interfaz nativa de Java que altera el modo de redondeo numérico utilizado en la multiplicación de una manera que Java no conoce aproximadamente) el código tendría alguna forma de saber o preocuparse si la multiplicación se realizó antes o después de d ().

De lo contrario, lo importante es que en el primer caso, una operación de suma actuará sobre a () yb (), y la otra sobre c () y d (); la multiplicación actuará sobre a () + b () y c () + d (). En el otro caso, la primera multiplicación actuará sobre b () yc (), la primera adición sobre a () y el producto mencionado anteriormente, y la segunda adición sobre la primera suma yd ().


Las expresiones se evalúan de izquierda a derecha. Los paréntesis (y la precedencia) simplemente expresan la agrupación, no expresan el orden de la evaluación.

Entonces

11 * (12 + 5) ++a ++a

es igual

187


int a = 10; a = ++a * ( ++a + 5);

las expresiones anteriores siempre se evalúan de izquierda a derecha, ya sea C o JAVA

en este caso está resolviendo así 11 * (12 + 5) lo que resulta en 11 * 17 = 187 // wrt java

pero si resolvemos la misma expresión wrt lenguaje C

entonces la respuesta cambia a medida que cambia la forma de evaluación

en c ocurre el primer pre-incremento / pre-decremento, entonces si "N" no hay veces pre inc / dec en la expresión, entonces inc / dec sucederá primero "N" no veces

entonces se sustituirá el mismo valor en cada aparición de la variable en la expresión y se calculará el valor de la expresión y después de que ocurra ese incremento / decremento posterior

es decir, a se incrementa a 11 y luego nuevamente 12 ya que hay dos incrementos para a en la expresión y luego la expresión se evalúa como

12 * (12 + 5) = 12 * 17 = 204 // wrt lenguaje C