增量逻辑
Incrementor logic
我正在尝试更深入地了解 post 和预增量器,但我对以下表达式有点困惑:
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
}
我知道我在某处缺少逻辑,但是在哪里?
我尝试过的:
- 从左到右(虽然我知道不推荐)
- 从最里面的括号开始。
感谢您的帮助
PS : 评论是我微积分的细节
编辑 1
我试图将 2
表达式中的硬编码值更改为其他值,结果总是 0
看这个例子:
int i = 0;
i = i+=(++i + (i+=32500 + --i) - ++i);
System.out.println(i); // Prints 0
这个表达式在逻辑上应该与 0
相去甚远,但它确实打印出来了。
当我使用负数时也会发生同样的情况:
int i = 0;
i = i+=(++i + (i+=(-32650) + --i) - ++i);
System.out.println(i); // Prints 0
编辑 2
现在,我将 i
的值更改为开头:
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
无论硬编码值是什么,它每次都会给出 i
的两倍。
好的,让我们分解每件事:
int i = 0; // i = 0, no big deal
然后从最里面的括号开始:
(i+=2 + --i)
- 它首先递减
i
并使用结果(-1
)
- 然后加 2 (
-1+2=1
)
- 并将结果添加到 i(运算开始时为 0)(
0+1=1=i
)
最后,重新分配忽略了第一个减量。
下一个括号:
i+= (++i + previous_result - ++i)
- 它增加了两个点
i
(++i
)
- 然后操作变成
(i+1) + previous_result - (i+2)
(注意增量是如何不同时的)给出 2 + 1 - 3 = 0
.
- 运算结果加到初始
i
(0
)
增量将再次被重新分配丢弃。
最后:
i = previous_result
给出 0 :)
这是考虑到您第一次编辑的逻辑(未知 X
):
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
}
技巧在这里:
+=
是一个 assignement operator,所以它是右结合的:在代码片段中,我添加了括号以更清楚地表达这一点
- 赋值表达式的结果是赋值发生后变量的值
- postfix increment operator
++
and postfix decrement operator --
将值加或减 1,结果存储回变量。
+
additive operator 先计算左操作数,再计算右操作数。
第二次编辑(添加了未知 I
):
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
}
括号优先。顺序将从最内到最外
(i+=2 + --i) =>i=i+=2==(2) --2 =0
(++i - ++i) =>1-1=0
i=i+ =0+0 =0
每个表达式的计算结果为 0
我建议如下:以不同的方式格式化代码,以便每行只有 1 个语句,例如
@Test
public void test() {
int i = 0;
i =
i+=
(
++i
+
(
i+=
2
+
--i
)
-
++i
);
System.out.println(i); // Prints 0 instead of 5
}
然后 运行 它在调试器下并始终按 F5 ("Step into")。这将帮助您了解对哪些订单商品进行评估:
int i=0;
i=
: ...(需要等待计算A的结果)
i+=
...(需要等待B)
++i
: i=1
i+=
...(需要等待C)
2+
--i
: 我=0
- ...: i=3(等待 C 的结果)
-
++i
: i=4 并且 - 的操作数也是 4
- ...: i=0(等待 B 的结果)
- ...: i=0(等待 A 的结果)
第10行总是会得到第3行的结果0
,所以i的初始值不会被整个操作改变。
引用 Java Language Specification, 15.7 Evaluation Order:
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.
所以,本质上,i += ++i
会记住左侧 i
的旧值,在 评估右侧。
请记住,操作数的计算顺序和运算符的优先级是两个不同的东西。
显示评估顺序,一步一步,保存值在 {braces} 中:
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
问题编辑的跟进
如果我们将初始值命名为I
,常量命名为N
:
int i = I;
i = i += (++i + (i += N + --i) - ++i);
那么我们可以看到值为:
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;
因为最高优先级 (...) 将首先被评估,然后是 ++ & -- 然后是剩余的运算符。
你的表情像
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
请将您的表达式完全括起来。您将了解表达式的评估顺序。
对于您的 EDIT 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
我追踪了 i 的值,结果如下:
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;
左数第2个i的值不为0,是右边所有运算完成后i的值
我正在尝试更深入地了解 post 和预增量器,但我对以下表达式有点困惑:
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
}
我知道我在某处缺少逻辑,但是在哪里?
我尝试过的:
- 从左到右(虽然我知道不推荐)
- 从最里面的括号开始。
感谢您的帮助
PS : 评论是我微积分的细节
编辑 1
我试图将 2
表达式中的硬编码值更改为其他值,结果总是 0
看这个例子:
int i = 0;
i = i+=(++i + (i+=32500 + --i) - ++i);
System.out.println(i); // Prints 0
这个表达式在逻辑上应该与 0
相去甚远,但它确实打印出来了。
当我使用负数时也会发生同样的情况:
int i = 0;
i = i+=(++i + (i+=(-32650) + --i) - ++i);
System.out.println(i); // Prints 0
编辑 2
现在,我将 i
的值更改为开头:
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
无论硬编码值是什么,它每次都会给出 i
的两倍。
好的,让我们分解每件事:
int i = 0; // i = 0, no big deal
然后从最里面的括号开始:
(i+=2 + --i)
- 它首先递减
i
并使用结果(-1
) - 然后加 2 (
-1+2=1
) - 并将结果添加到 i(运算开始时为 0)(
0+1=1=i
)
最后,重新分配忽略了第一个减量。
下一个括号:
i+= (++i + previous_result - ++i)
- 它增加了两个点
i
(++i
) - 然后操作变成
(i+1) + previous_result - (i+2)
(注意增量是如何不同时的)给出2 + 1 - 3 = 0
. - 运算结果加到初始
i
(0
)
增量将再次被重新分配丢弃。
最后:
i = previous_result
给出 0 :)
这是考虑到您第一次编辑的逻辑(未知 X
):
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
}
技巧在这里:
+=
是一个 assignement operator,所以它是右结合的:在代码片段中,我添加了括号以更清楚地表达这一点- 赋值表达式的结果是赋值发生后变量的值
- postfix increment operator
++
and postfix decrement operator--
将值加或减 1,结果存储回变量。 +
additive operator 先计算左操作数,再计算右操作数。
第二次编辑(添加了未知 I
):
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
}
括号优先。顺序将从最内到最外
(i+=2 + --i) =>i=i+=2==(2) --2 =0
(++i - ++i) =>1-1=0
i=i+ =0+0 =0
每个表达式的计算结果为 0
我建议如下:以不同的方式格式化代码,以便每行只有 1 个语句,例如
@Test
public void test() {
int i = 0;
i =
i+=
(
++i
+
(
i+=
2
+
--i
)
-
++i
);
System.out.println(i); // Prints 0 instead of 5
}
然后 运行 它在调试器下并始终按 F5 ("Step into")。这将帮助您了解对哪些订单商品进行评估:
int i=0;
i=
: ...(需要等待计算A的结果)i+=
...(需要等待B)++i
: i=1i+=
...(需要等待C)2+
--i
: 我=0- ...: i=3(等待 C 的结果)
-
++i
: i=4 并且 - 的操作数也是 4- ...: i=0(等待 B 的结果)
- ...: i=0(等待 A 的结果)
第10行总是会得到第3行的结果0
,所以i的初始值不会被整个操作改变。
引用 Java Language Specification, 15.7 Evaluation Order:
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.
所以,本质上,i += ++i
会记住左侧 i
的旧值,在 评估右侧。
请记住,操作数的计算顺序和运算符的优先级是两个不同的东西。
显示评估顺序,一步一步,保存值在 {braces} 中:
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
问题编辑的跟进
如果我们将初始值命名为I
,常量命名为N
:
int i = I;
i = i += (++i + (i += N + --i) - ++i);
那么我们可以看到值为:
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;
因为最高优先级 (...) 将首先被评估,然后是 ++ & -- 然后是剩余的运算符。 你的表情像
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
请将您的表达式完全括起来。您将了解表达式的评估顺序。
对于您的 EDIT 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
我追踪了 i 的值,结果如下:
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;
左数第2个i的值不为0,是右边所有运算完成后i的值