Saya memiliki sedikit kode sederhana yang seharusnya menjadi loop tanpa akhir karena x
akan selalu tumbuh dan akan selalu tetap lebih besar dari j
.
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
}
System.out.println(y);
tetapi sebagaimana adanya, ia mencetak y
dan tidak berputar tanpa henti. Saya tidak tahu mengapa. Namun, ketika saya menyesuaikan kode dengan cara berikut:
int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
x = x + y;
System.out.println(y);
}
System.out.println(y);
Ini menjadi lingkaran tanpa akhir dan saya tidak tahu mengapa. Apakah java mengenali loop tak berujung dan melewatkannya pada situasi pertama tetapi harus mengeksekusi pemanggilan metode pada situasi kedua sehingga berperilaku seperti yang diharapkan? Bingung :)
java
for-loop
infinite-loop
Omar
sumber
sumber
x
tumbuh lebih cepat daripada variabel loopj
. Dengan kata lain,j
tidak akan pernah mencapai batas atas, karenanya loop akan berjalan "selamanya." Yah, tidak selamanya, kemungkinan besar Anda akan mendapatkan luapan di beberapa titik.y
238609294 kaliSystem.out.println(x)
alih-alihy
di bagian akhir akan langsung menunjukkan apa masalahnyaJawaban:
Kedua contoh tersebut tidak terbatas.
Masalahnya adalah batasan
int
tipe di Java (atau hampir semua bahasa umum lainnya). Ketika nilaix
mencapai0x7fffffff
, menambahkan nilai positif apa pun akan menghasilkan luapan danx
menjadi negatif, oleh karena itu lebih rendah darij
.Perbedaan antara loop pertama dan kedua adalah kode bagian dalam membutuhkan lebih banyak waktu dan mungkin perlu beberapa menit sampai
x
overflow. Untuk contoh pertama mungkin memerlukan waktu kurang dari detik atau kemungkinan besar kode akan dihapus oleh pengoptimal karena tidak berpengaruh apa pun.Seperti yang disebutkan dalam pembahasan, waktu akan sangat bergantung pada bagaimana OS men-buffer keluaran, apakah itu dikeluarkan ke emulator terminal, dll., Sehingga bisa jadi lebih lama dari beberapa menit.
sumber
println()
pada Windows adalah operasi pemblokiran, sedangkan pada (beberapa?) Unix itu buffer sehingga berjalan lebih cepat. Coba juga gunakanprint()
, buffer mana sampai mencapai\n
(atau buffer terisi, atauflush()
disebut)Karena mereka dideklarasikan sebagai int, setelah mencapai nilai max, loop akan putus karena nilai x akan menjadi negatif.
Tetapi ketika System.out.println ditambahkan ke loop, kecepatan eksekusi menjadi terlihat (karena keluaran ke konsol akan memperlambat kecepatan eksekusi). Namun, jika Anda membiarkan program ke-2 (program dengan syso di dalam perulangan) berjalan cukup lama, program tersebut akan memiliki perilaku yang sama seperti yang pertama (program tanpa syso di dalam perulangan).
sumber
Ada dua alasan untuk ini:
Java mengoptimalkan
for
perulangan dan karena tidak ada penggunaanx
setelah perulangan, cukup hapus perulangan. Anda dapat memeriksa ini dengan meletakkanSystem.out.println(x);
pernyataan setelah pengulangan.Ada kemungkinan bahwa Java tidak benar-benar mengoptimalkan loop dan menjalankan program dengan benar dan pada akhirnya
x
akan menjadi terlalu besarint
dan meluap. Integer overflow kemungkinan besar akan membuat integerx
menjadi negatif yang akan lebih kecil dari j sehingga akan keluar dari loop dan mencetak nilaiy
. Ini juga dapat diperiksa dengan menambahkanSystem.out.println(x);
setelah perulangan.Juga, bahkan dalam kasus pertama akhirnya overflow akan terjadi sehingga rendering ke kasus kedua sehingga tidak akan pernah menjadi loop tanpa akhir yang sebenarnya.
sumber
sysout
sangat lambat untuk menambahkan ilusi putaran tak terbatas.Keduanya bukanlah loop tanpa akhir, awalnya j = 0, selama j <x, j meningkat (j ++), dan j adalah integer sehingga loop akan berjalan hingga mencapai nilai maksimum lalu meluap (Overflow Integer adalah kondisinya yang terjadi jika hasil operasi aritmatika, seperti perkalian atau penjumlahan, melebihi ukuran maksimum jenis bilangan bulat yang digunakan untuk menyimpannya.). untuk contoh kedua sistem hanya mencetak nilai y sampai pengulangan putus.
jika Anda mencari contoh loop tanpa akhir, akan terlihat seperti ini
int x = 6; for (int i = 0; x < 10; i++) { System.out.println("Still Looping"); }
karena (x) tidak akan pernah mencapai nilai 10;
Anda juga bisa membuat loop tak terbatas dengan loop for ganda:
int i ; for (i = 0; i <= 10; i++) { for (i = 0; i <= 5; i++){ System.out.println("Repeat"); } }
loop ini tidak terbatas karena loop for pertama mengatakan i <10, yang benar sehingga masuk ke loop for kedua dan loop for kedua meningkatkan nilai (i) hingga == 5. Kemudian melanjutkan ke loop pertama for loop lagi karena i <10, proses terus berulang sendiri karena me-reset setelah for loop kedua
sumber
Ini adalah pengulangan terbatas karena setelah nilai
x
melebihi2,147,483,647
(yang merupakan nilai maksimum dari sebuahint
),x
akan menjadi negatif dan tidak lebih besar dari yangj
lainnya, baik Anda mencetak y atau tidak.Anda cukup mengubah nilai
y
menjadi100000
dan mencetaky
dalam pengulangan dan pengulangan akan segera berhenti.Alasan mengapa Anda merasa itu menjadi tak terbatas adalah karena
System.out.println(y);
membuat kode dieksekusi jauh lebih lambat daripada tanpa tindakan apa pun.sumber
Masalah yang menarik Sebenarnya dalam kedua kasus loop tidak ada habisnya
Tetapi perbedaan utama di antara mereka adalah kapan itu akan berakhir dan berapa banyak waktu yang
x
dibutuhkan untuk melebihiint
nilai maks yang2,147,483,647
setelah itu akan mencapai keadaan luapan dan loop akan berakhir.Cara terbaik untuk memahami masalah ini adalah dengan menguji contoh sederhana dan mempertahankan hasilnya.
Contoh :
for(int i = 10; i > 0; i++) {} System.out.println("finished!");
Keluaran:
finished! BUILD SUCCESSFUL (total time: 0 seconds)
Setelah menguji loop tak terbatas ini, dibutuhkan waktu kurang dari 1 detik untuk berhenti.
for(int i = 10; i > 0; i++) { System.out.println("infinite: " + i); } System.out.println("finished!");
Keluaran:
infinite: 314572809 infinite: 314572810 infinite: 314572811 . . . infinite: 2147483644 infinite: 2147483645 infinite: 2147483646 infinite: 2147483647 finished! BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)
Pada kasus pengujian ini, Anda akan melihat perbedaan besar dalam waktu yang dibutuhkan untuk menghentikan dan menyelesaikan program.
Jika Anda tidak sabar, Anda akan berpikir loop ini tidak ada habisnya dan tidak akan berakhir tetapi pada kenyataannya akan memakan waktu berjam-jam untuk mengakhiri dan mencapai keadaan overflow pada
i
nilainya.Akhirnya kami menyimpulkan setelah kami meletakkan pernyataan print di dalam for loop bahwa itu akan membutuhkan lebih banyak waktu daripada loop dalam kasus pertama tanpa pernyataan print.
Waktu yang dibutuhkan untuk menjalankan program tergantung pada spesifikasi komputer Anda khususnya kekuatan pemrosesan (kapasitas prosesor), sistem operasi dan IDE Anda yang sedang menyusun program.
Saya menguji kasus ini pada:
Lenovo 2,7 GHz Intel Core i5
OS: Windows 8.1 64x
IDE: NetBeans 8.2
Dibutuhkan sekitar 8 jam (486 menit) untuk menyelesaikan program ini.
Anda juga dapat melihat bahwa kenaikan langkah di loop for
i = i + 1
adalah faktor yang sangat lambat untuk mencapai nilai int maksimal.Kita dapat mengubah faktor ini dan membuat peningkatan langkah lebih cepat untuk menguji loop dalam waktu yang lebih singkat.
jika kita menempatkan
i = i * 10
dan mengujinya:for(int i = 10; i > 0; i*=10) { System.out.println("infinite: " + i); } System.out.println("finished!");
Keluaran:
infinite: 100000 infinite: 1000000 infinite: 10000000 infinite: 100000000 infinite: 1000000000 infinite: 1410065408 infinite: 1215752192 finished! BUILD SUCCESSFUL (total time: 0 seconds)
Seperti yang Anda lihat, ini sangat cepat dibandingkan dengan loop sebelumnya
dibutuhkan kurang dari 1 detik untuk menghentikan dan menyelesaikan program yang sedang berjalan.
Setelah contoh tes ini saya pikir itu harus menjelaskan masalah dan membuktikan validitas Zbynek Vyskovsky - jawaban kvr000 , juga akan menjadi jawaban untuk pertanyaan ini .
sumber