У меня был простой фрагмент кода, который должен был быть бесконечным циклом, поскольку 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);
Это превращается в бесконечный цикл, и я не знаю почему. Распознает ли java свой бесконечный цикл и пропускает его в первой ситуации, но должна ли выполнить вызов метода во второй, чтобы вести себя так, как ожидалось? Смущенный :)
x
растет быстрее, чем переменная циклаj
. Другими словами,j
никогда не достигнет верхней границы, следовательно, цикл будет работать «вечно». Ну, не навсегда, скорее всего, в какой-то момент у вас будет переполнение.y
238609294 разаSystem.out.println(x)
вместо того , чтобыy
в конце сразу показать, в чем проблемаОтветы:
Оба примера не бесконечны.
Проблема заключается в ограничении
int
типа в Java (или почти любом другом распространенном языке). Когда значениеx
достигает0x7fffffff
, добавление любого положительного значения приведет к переполнению, а значениеx
станет отрицательным, поэтому будет меньшеj
.Разница между первым и вторым циклами заключается в том, что внутренний код занимает гораздо больше времени, и до
x
переполнения может потребоваться несколько минут . Для первого примера это может занять меньше секунды или, скорее всего, код будет удален оптимизатором, так как это не имеет никакого эффекта.Как упоминалось в обсуждении, время будет сильно зависеть от того, как ОС буферизует вывод, выводит ли он на эмулятор терминала и т. Д., Поэтому оно может быть намного больше нескольких минут.
источник
println()
в Windows - это операция блокировки, тогда как в (некоторых?) Unix она буферизуется, поэтому выполняется намного быстрее. Также попробуйте использоватьprint()
, which buffers, пока он не достигнет\n
(или буфер заполнится, или неflush()
будет вызван)Поскольку они объявлены как int, при достижении максимального значения цикл прервется, поскольку значение x станет отрицательным.
Но когда в цикл добавляется System.out.println, скорость выполнения становится видимой (поскольку вывод на консоль замедляет скорость выполнения). Однако, если вы позволите второй программе (с syso внутри цикла) работать достаточно долго, она должна иметь то же поведение, что и первая (та, которая без syso внутри цикла).
источник
На это может быть две причины:
Java оптимизирует
for
цикл, и, посколькуx
после цикла не используется , просто удаляет цикл. Вы можете проверить это, поместивSystem.out.println(x);
оператор после цикла.Возможно, что Java на самом деле не оптимизирует цикл, а правильно выполняет программу и в конечном итоге
x
станет слишком большим дляint
переполнения. Целочисленное переполнение, скорее всего, сделает целое числоx
отрицательным, которое будет меньше j, поэтому оно выйдет из цикла и напечатает значениеy
. Это также можно проверить, добавивSystem.out.println(x);
после цикла.Кроме того, даже в первом случае в конечном итоге произойдет переполнение, что переведет его во второй случай, так что это никогда не будет истинным бесконечным циклом.
источник
sysout
так медленно добавляет иллюзию бесконечного цикла.Оба они не являются бесконечными циклами, изначально j = 0, пока j <x, j увеличивается (j ++), а j является целым числом, поэтому цикл будет выполняться до тех пор, пока не достигнет максимального значения, а затем переполнение (целочисленное переполнение - это условие это происходит, когда результат арифметической операции, такой как умножение или сложение, превышает максимальный размер целочисленного типа, используемого для его хранения.). для второго примера система просто печатает значение y до тех пор, пока цикл не прервется.
если вы ищете пример бесконечного цикла, он должен выглядеть так
int x = 6; for (int i = 0; x < 10; i++) { System.out.println("Still Looping"); }
потому что (x) никогда не достигнет значения 10;
вы также можете создать бесконечный цикл с двойным циклом for:
int i ; for (i = 0; i <= 10; i++) { for (i = 0; i <= 5; i++){ System.out.println("Repeat"); } }
этот цикл бесконечен, потому что первый цикл for говорит, что i <10, что верно, поэтому он переходит во второй цикл for, а второй цикл for увеличивает значение (i), пока оно не станет == 5. Затем он перейдет в первый for цикл снова, потому что i <10, процесс продолжает повторяться, потому что он сбрасывается после второго цикла for
источник
Это конечный цикл, потому что после того, как значение
x
превышает2,147,483,647
(которое является максимальным значением anint
),x
станет отрицательным и не больше, чем когда-j
либо, независимо от того, печатаете ли вы y или нет.Вы можете просто изменить значение
y
на100000
и печататьy
в цикле, и цикл очень скоро прервется.Причина, по которой вы чувствуете, что это стало бесконечным, заключается в том, что
System.out.println(y);
код выполнялся намного медленнее, чем без каких-либо действий.источник
Интересная проблема На самом деле в обоих случаях цикл не бесконечен
Но основное различие между ними заключается в том, когда он завершится и сколько времени
x
потребуется, чтобы превысить максимальное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
значению потребуется несколько часов .Наконец, после помещения оператора печати внутрь цикла for мы пришли к выводу, что это займет гораздо больше времени, чем цикл в первом случае без оператора печати.
Время, необходимое для запуска программы, зависит от технических характеристик вашего компьютера, в частности от вычислительной мощности (мощности процессора), операционной системы и вашей среды разработки, которая компилирует программу.
Я тестирую этот случай на:
Lenovo 2,7 ГГц Intel Core i5
ОС: Windows 8.1 64x
IDE: NetBeans 8.2
Завершение программы занимает около 8 часов (486 минут).
Также вы можете заметить, что приращение шага в цикле for
i = i + 1
является очень медленным фактором для достижения максимального значения 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 секунды.
После этого тестового примера, я думаю, он должен прояснить проблему и доказать справедливость ответа Збынека Высковского - kvr000 , также он будет ответом на этот вопрос .
источник