java - numero - Lógica de incremento
for java (7)
Estoy tratando de profundizar con post y pre incrementos, pero estoy un poco atascado con la siguiente expresión:
public static void main(String[] args) {
int i = 0;
i = i+=(++i + (i+=2 + --i) - ++i);
// i = 0 + (++i + (i+=2 + --i) - ++i);
// i = 0 + (1 + (3 + 2) - 1);
// i = 0 + (6 - 1);
System.out.println(i); // Prints 0 instead of 5
}
Sé que me falta la lógica en algún lugar, pero ¿dónde?
Lo que probé:
- Ir de izquierda a derecha (aunque sé que no es recomendable)
- Yendo desde el soporte interior y comenzando desde allí.
Gracias por la ayuda
PD: Los comentarios son los detalles de mi cálculo.
EDITAR 1
Traté de cambiar el valor codificado de la expresión de
2
a otra cosa y el resultado siempre da
0
Mira este ejemplo:
int i = 0;
i = i+=(++i + (i+=32500 + --i) - ++i);
System.out.println(i); // Prints 0
Esta expresión no debería estar lógicamente cerca de
0
pero de alguna manera la imprime.
Lo mismo sucede cuando uso un negativo:
int i = 0;
i = i+=(++i + (i+=(-32650) + --i) - ++i);
System.out.println(i); // Prints 0
EDITAR 2
Ahora, cambié el valor de
i
para empezar:
int i = 1;
i = i+=(++i + (i+=2 + --i) - ++i);
System.out.println(i); // Prints 2
i = 2;
i = i+=(++i + (i+=10000 + --i) - ++i);
System.out.println(i); // Prints 4
i = 3;
i = i+=(++i + (i+=(-32650) + --i) - ++i);
System.out.println(i); // Prints 6
Da el doble de
i
cada vez, sea cual sea el valor codificado.
Citando la especificación del lenguaje Java, 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 .
El operando de la izquierda de un operador binario parece estar completamente evaluado antes de evaluar cualquier parte del operando de la derecha.
Si el operador es un operador de asignación compuesta ( §15.26.2 ), entonces la evaluación del operando de la izquierda incluye recordar la variable que denota el operando de la izquierda y buscar y guardar el valor de esa variable para usar en la operación binaria implícita .
Entonces, esencialmente,
i += ++i
recordaré el valor anterior de
i
en el lado izquierdo,
antes de
evaluar el lado derecho.
Recuerde, el orden de evaluación de los operandos y la precedencia de los operadores son dos cosas diferentes.
Mostrando el orden de evaluación, paso a paso, con el valor guardado en {llaves}:
int i = 0;
i = i += (++i + (i += 2 + --i) - ++i); // i = 0
i{0} = i += (++i + (i += 2 + --i) - ++i); // i = 0
i{0} = i{0} += (++i + (i += 2 + --i) - ++i); // i = 0
i{0} = i{0} += (1 + (i += 2 + --i) - ++i); // i = 1
i{0} = i{0} += (1 + (i{1} += 2 + --i) - ++i); // i = 1
i{0} = i{0} += (1 + (i{1} += 2 + 0 ) - ++i); // i = 0
i{0} = i{0} += (1 + (i{1} += 2 ) - ++i); // i = 0
i{0} = i{0} += (1 + 3 - ++i); // i = 3
i{0} = i{0} += (4 - ++i); // i = 3
i{0} = i{0} += (4 - 4 ); // i = 4
i{0} = i{0} += 0 ; // i = 4
i{0} = 0 ; // i = 0
0 ; // i = 0
Seguimiento de ediciones a la pregunta
Si nombramos el valor inicial
I
y la constante
N
:
int i = I;
i = i += (++i + (i += N + --i) - ++i);
Entonces podemos ver que los valores son:
i{I} = i{I} += ((I+1) + (i{I+1} += N + I) - ((I+1+N+I)+1));
i{I} = i{I} += (I + 1 + (I + 1 + N + I) - (I + 1 + N + I + 1));
i{I} = i{I} += (I + 1 + I + 1 + N + I - I - 1 - N - I - 1);
i{I} = i{I} += I;
i{I} = I + I;
i = 2 * I;
Debido a la mayor precedencia (...) se evaluará primero luego ++ y - y luego los operadores restantes. Tu expresión es como
i = i += ( (++i) + (i+=2 + (--i)) - (++i) );
//i = i = i + ( (++i) + (i+=2 + (--i)) - (++i) );
//i = i = 0 + ( (++i) + (i+=2 + (--i)) - (++i) );
//i = i = 0 + ( (1) + (i+=2 + (--i)) - (++i) );
//i = i = 0 + ( (1) + (i+=2 + (0)) - (++i) );
//i = i = 0 + ( (1) + (2 + (0)) - (++i) );
//i = i = 0 + ( (1) + (2) - (++i) );
//i = i = 0 + ( (1) + (2) - (3) );
//i = i = 0 + ( 3 - 3 );
//i = i = 0 + ( 0 );
//i = 0
Por favor, escribe entre paréntesis tu expresión. Comprenderá el orden de expresión de evaluación.
Para su EDITAR 1
i = i+=( (++i) + (i+=32500 + (--i) ) - (++i) );
// 0 + ( (++i) + (i+=32500 + (--i) ) - (++i) ); // i = 0
// 0 + ( (1) + (i+=32500 + (--i) ) - (++i) ); // i = 1
// 0 + ( (1) + (i+=32500 + (0) ) - (++i) ); // i = 0
// 0 + ( (1) + (32500 + (0) ) - (++i) ); // i = 32500
// 0 + ( (1) + (32500) - (++i) ); // i = 32500
// 0 + ( (1) + (32500) - (32501) ); // i = 32501
// 0 + ( 32501 - 32501 ); // i = 32501
// 0 // i = 0
Esta es la lógica teniendo en cuenta su primera edición (con una
X
desconocida):
public static void main(String[] args) {
int i = 0;
i = i+=(++i + (i+=X + --i) - ++i);
// i = 0 += (++i + ((i += (X + --i)) - ++i));
// i = 0 += (1 + ((i += (X + --i)) - ++i)); // i = 1
// i = 0 += (1 + ((1 += (X + --i)) - ++i)); // i = 1 and i will then take the result of 1 += (X + --i)
// i = 0 += (1 + ((1 += (X + 0)) - ++i)); // i = 0 and i will then take the result of 1 += (X + 0)
// i = 0 += (1 + (X + 1 - ++i)); // i = X + 1
// i = 0 += (1 + (X + 1 - X - 2)); // i = X + 2
// i = 0 += (0); // i = X + 2
// i = 0;
System.out.println(i); // Prints 0
}
Trucos aquí:
-
+=
es un operador de asignación, por lo que es asociativo a la derecha: en los fragmentos, agregué paréntesis para expresar esto más claramente - El resultado de la expresión de asignación es el valor de la variable después de que se haya producido la asignación.
-
El
operador de incremento de postfix
++
y el operador de disminución de postfix--
suman o restan 1 del valor y el resultado se almacena nuevamente en la variable. -
El
operador aditivo
+
primero calcula el operando de la izquierda y luego el operando de la derecha.
Para su segunda edición (con un desconocido
I
agregué):
public static void main(String[] args) {
int i = I;
i = i+=(++i + (i+=X + --i) - ++i);
// i = I += (++i + ((i += (X + --i)) - ++i));
// i = I += (I+1 + ((i += (X + --i)) - ++i)); // i = I+1
// i = I += (I+1 + ((I+1 += (X + --i)) - ++i)); // i = I+1 and i will then take the result of I+1 += (X + --i)
// i = I += (I+1 + ((I+1 += (X + I)) - ++i)); // i = I and i will then take the result of I+1 += (X + I)
// i = I += (I+1 + (X+2*I+1 - ++i)); // i = X + 2*I + 1
// i = I += (I+1 + (X+2*I+1 - X-2*I-2)); // i = X + 2*I + 2
// i = I += (I); // i = X + 2*I + 2
// i = 2 * I;
System.out.println(i); // Prints 2 * I
}
La parálisis tiene prioridad. el orden sería de lo más interno a lo más externo
(i+=2 + --i) =>i=i+=2==(2) --2 =0
(++i - ++i) =>1-1=0
i=i+ =0+0 =0
Cada expresión se evalúa a 0
Ok, analicemos todo:
int i = 0; // i = 0, no big deal
Luego, comenzando por el paréntesis más interno:
(i+=2 + --i)
-
primero disminuye
i
usa el resultado (-1
) -
luego agregue 2 (
-1+2=1
) -
y agregue el resultado a i (que es 0 al comienzo de la operación) (
0+1=1=i
)
Al final, el primer decremento es ignorado por la reasignación.
Siguiente paréntesis:
i+= (++i + previous_result - ++i)
-
aumenta el
i
(con++i
) en dos puntos -
entonces la operación se convierte en
(i+1) + previous_result - (i+2)
(observe cómo el incremento no es simultáneo) que da2 + 1 - 3 = 0
. -
el resultado de la operación se agrega a la inicial
i
(0
)
Nuevamente, el incremento se descartará mediante la reasignación.
finalmente:
i = previous_result
Lo que da 0 :)
Rastreé el valor de iy aquí están los resultados:
i = i+=(++i + (i+=2 + --i) - ++i);
initialization: i = 0;
++i: i = 1;(1st one) and store this value
(i+=2 + --i): In it
--i: i = 0;(i was changed by the previous ++i)
i += 2 + 0: i = 2;(value of the inner (i+=2 + --i), store it)
++i: i = 3;
1 + 2 -3: i = 0;
i += 0: i = 0;
El valor de la segunda i desde la izquierda no es cero, es el valor de i después de que todas las operaciones a la derecha hayan finalizado.
Sugiero lo siguiente: formatee el código de manera diferente, de modo que solo haya 1 instrucción por línea, por ejemplo
@Test
public void test() {
int i = 0;
i =
i+=
(
++i
+
(
i+=
2
+
--i
)
-
++i
);
System.out.println(i); // Prints 0 instead of 5
}
Luego ejecútelo debajo del depurador y presione F5 ("Entrar") siempre. Esto lo ayudará a comprender en qué orden se evalúan los artículos:
-
int i=0;
-
i=
: ... (necesita esperar el resultado del cálculo A) -
i+=
... (necesita esperar B) -
++i
: i = 1 -
i+=
... (necesita esperar C) -
2+
-
--i
: i = 0 - ...: i = 3 (resultado de la espera C)
-
-
-
++i
: i = 4 y el operando de - también es 4 - ...: i = 0 (resultado de la espera B)
- ...: i = 0 (resultado de la espera A)
La línea 10 siempre hará el resultado de la línea 3
0
, por lo que el valor inicial de i nunca será cambiado por toda la operación.