Похоже, бесконечный цикл завершается, если не используется System.out.println

У меня был простой бит кода, который был предполагаемым бесконечным циклом, так как x всегда будет расти и всегда будет оставаться больше j.

int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
   x = x + y;
}
System.out.println(y);

но как есть, он печатает y и не работает бесконечно. Я не могу понять, почему. Однако, когда я настраиваю код следующим образом:

int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
    x = x + y;
    System.out.println(y);
}
System.out.println(y);

Он становится бесконечным циклом, и я понятия не имею, почему. Ява признает его бесконечный цикл и пропускает его в первой ситуации, но ему нужно выполнить вызов метода во втором, чтобы он вел себя так, как ожидалось? Confused:)

Ответ 1

Оба примера не бесконечны.

Проблема заключается в ограничении типа int в Java (или почти любом другом общем языке). Когда значение x достигает 0x7fffffff, добавление любого положительного значения приведет к переполнению, а x станет отрицательным, поэтому ниже j.

Разница между первым и вторым циклами заключается в том, что внутренний код занимает гораздо больше времени, и это займет, вероятно, несколько минут до переполнения x. В первом примере это может занять менее секунды или, скорее всего, код будет удален оптимизатором, так как он не имеет никакого эффекта.

Как упоминалось в обсуждении, время будет сильно зависеть от того, как ОС буферизует выход, выводит ли он на эмулятор терминала и т.д., поэтому он может быть намного выше, чем несколько минут.

Ответ 2

Так как они объявлены как int, как только он достигает максимального значения, цикл будет прерываться, так как значение x станет отрицательным.

Но когда System.out.println добавляется в цикл, скорость выполнения становится видимой (поскольку вывод на консоль замедляет скорость выполнения). Однако, если вы позволите 2-й программе (той, у которой есть syso внутри цикла) работает достаточно долго, она должна иметь такое же поведение, как и первое (одно без сисо внутри цикла).

Ответ 3

Для этого могут быть две причины:

  • Java оптимизирует цикл for и, поскольку после цикла не используется x, просто удаляет цикл. Вы можете проверить это, поставив оператор System.out.println(x); после цикла.

  • Возможно, что Java фактически не оптимизирует цикл, и он правильно выполняет программу, и в конечном итоге x будет слишком большим для int и переполнения. Целочисленное переполнение, скорее всего, сделает целое число x отрицательным, которое будет меньше j, и поэтому оно выйдет из цикла и напечатает значение y. Это также можно проверить, добавив System.out.println(x); после цикла.

Кроме того, даже в первом случае произойдет переполнение, что приведет к второму случаю, поэтому он никогда не станет истинным бесконечным циклом.

Ответ 4

Они оба не бесконечные петли, первоначально j = 0, пока j < x, j увеличивается (j ++), а j является целым числом поэтому цикл будет работать до тех пор, пока он не достигнет максимального значения, а затем переполнения (An Integer Overflow - это условие, которое возникает, когда результат арифметической операции, такой как умножение или добавление, превышает максимальный размер целочисленного типа, используемого для его хранения.), для второго примера система просто печатает значение y до тех пор, пока цикл не сломается.

Если вы ищете пример бесконечного цикла, это должно выглядеть так.

int x = 6;

for (int i = 0; x < 10; i++) {
System.out.println("Still Looping");
}

потому что (x) никогда не достигнет значения 10;

вы также можете создать бесконечный цикл с циклом double for:

int i ;

  for (i = 0; i <= 10; i++) {
      for (i = 0; i <= 5; i++){
         System.out.println("Repeat");   
      }
 }

этот цикл бесконечен, потому что первый для цикла говорит я < 10, что верно, так что он переходит во второй цикл, а второй для цикла увеличивает значение (i) до тех пор, пока оно не будет равно 5. Затем оно переходит в первое для петля снова, поскольку я < 10, процесс продолжает повторяться, потому что он сбрасывается после второго цикла

Ответ 5

Это конечный цикл, потому что как только значение x превышает 2,147,483,647 (что является максимальным значением int), x станет больше и не больше j, независимо от того, print y или нет.

Вы можете просто изменить значение y на 100000 и напечатать y в цикле, и цикл будет очень скоро разорваться.

Причина, по которой вы чувствуете, что она стала бесконечной, заключается в том, что System.out.println(y); заставил код работать намного медленнее, чем без каких-либо действий.

Ответ 6

Интересная проблема На самом деле в обоих случаях цикл не бесконечен

Но основное различие между ними заключается в том, когда оно закончится и сколько времени x примет значение max int, которое равно 2,147,483,647, после чего оно достигнет состояния переполнения и цикл завершится.

Лучший способ понять эту проблему - проверить простой пример и сохранить его результаты.

Пример:

for(int i = 10; i > 0; i++) {}
System.out.println("finished!");

Вывод:

finished!
BUILD SUCCESSFUL (total time: 0 seconds)

После тестирования этого бесконечного цикла для завершения потребуется менее 1 секунды.

for(int i = 10; i > 0; i++) {
    System.out.println("infinite: " + i);
}
System.out.println("finished!");

Вывод:

infinite: 314572809
infinite: 314572810
infinite: 314572811
.
.
.
infinite: 2147483644
infinite: 2147483645
infinite: 2147483646
infinite: 2147483647
finished!
BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)

В этом случае вы заметите огромную разницу в времени, затраченном на прекращение и завершение работы программы.

Если вы не испытываете терпения, вы подумаете, что этот цикл бесконечен и не будет завершен, но на самом деле для завершения и достижения состояния переполнения потребуется от нескольких часов до i.

Наконец, мы закончили после того, как мы положили инструкцию print внутри цикла for, что в первом случае это займет гораздо больше времени, чем цикл, без инструкции печати. ​​

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

Я проверяю этот случай на:

Lenovo 2.7 ГГц Intel Core i5

ОС: Windows 8.1 64x

IDE: NetBeans 8.2

Для завершения программы требуется около 8 часов (486 минут).

Также вы можете заметить, что шаг шага в цикле for i = i + 1 является очень медленным фактором для достижения значения max int.

Мы можем изменить этот коэффициент и сделать шаг с шагом более быстрым, чтобы проверить цикл за меньшее время.

если мы положим i = i * 10 и протестируем его:

for(int i = 10; i > 0; i*=10) {
           System.out.println("infinite: " + i);
}
     System.out.println("finished!");

Вывод:

infinite: 100000
infinite: 1000000
infinite: 10000000
infinite: 100000000
infinite: 1000000000
infinite: 1410065408
infinite: 1215752192
finished!
BUILD SUCCESSFUL (total time: 0 seconds)

Как вы видите, это очень быстро по сравнению с предыдущим циклом

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

После этого тестового примера я думаю, что он должен прояснить проблему и доказать достоверность ответа Zbynek Vyskovsky - kvr000, и это будет ответ на этот вопрос.