Подтвердить что ты не робот

Логика нарастания

Я пытаюсь углубиться в пост и pre инкременты, но немного застрял со следующим выражением:

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, независимо от того, какое значение имеет жесткое кодирование.

4b9b3361

Ответ 1

Цитата Спецификация языка Java, 15.7 Порядок оценки:

Язык программирования Java гарантирует, что операнды операторов будут оцениваться в определенном порядке оценки, а именно: от слева направо.

Локальный операнд двоичного оператора оказывается полностью оценен до того, как будет оценена любая часть правого операнда.

Если оператор является оператором составного присваивания (§15.26.2), то оценка левого операнда включает в себя оба запоминание переменной, которую обозначает левый операнд, и выборки и сохранение этого значения переменной для использования в подразумеваемой двоичной операции.

Итак, по существу, 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;

Ответ 2

Это логика с учетом вашего первого редактирования (с неизвестным 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
}

Трюки здесь:

Для вашего второго редактирования (с неизвестным 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
}

Ответ 3

Я предлагаю следующее: форматировать код по-разному, так что в строке есть только 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 ( "Шаг в" ). Это поможет вам понять, какие элементы заказа оцениваются:

  • int i=0;
  • i=:... (нужно ждать результата вычисления A)
  • i+=... (нужно ждать B)
  • ++i: я = 1
  • i+=... (необходимо подождать C)
  • 2+
  • --i: я = 0
  • ...: я = 3 (результат для ожидания C)
  • -
  • ++i: я = 4 и операнд - также 4
  • ...: я = 0 (результат для ожидания B)
  • ...: я = 0 (результат для ожидания A)

Строка 10 всегда будет делать результат строки 3 0, поэтому начальное значение я никогда не будет изменено всей операцией.

Ответ 4

Хорошо, пусть сломает все:

int i = 0; // i = 0, no big deal

Затем, начиная с самой внутренней скобки:

(i+=2 + --i)
  • сначала уменьшите i и используйте результат (-1)
  • затем добавьте 2 (-1+2=1)
  • и добавьте результат в я (который равен 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:)

Ответ 5

Из-за наивысшего приоритета (...) сначала будет оцениваться ++ и - и затем остальных операторов. Ваше выражение похоже на

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

Ответ 6

Я проследил значение я и вот результаты:

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;

Значение второго я слева не равно нулю, это значение я после завершения всех операций справа.

Ответ 7

Паратезис имеет приоритет. порядок будет от внутреннего до внешнего

(i+=2 + --i) =>i=i+=2==(2) --2 =0 
(++i - ++i)  =>1-1=0 
i=i+ =0+0 =0

Каждое выражение оценивается как 0