Saya memiliki program sederhana:
public class Mathz {
static int i = 1;
public static void main(String[] args) {
while (true){
i = i + i;
System.out.println(i);
}
}
}
Ketika saya menjalankan program ini, yang saya lihat hanyalah 0
untuk i
output saya. Saya akan mengharapkan putaran pertama kami akan i = 1 + 1
, diikuti oleh i = 2 + 2
, diikuti oleh i = 4 + 4
dll.
Apakah ini karena fakta bahwa segera setelah kami mencoba mendeklarasikan ulang i
di sisi kiri, nilainya disetel ulang ke 0
?
Jika ada yang bisa menunjukkan saya ke detail yang lebih baik dari ini, itu akan bagus.
Ubah int
menjadi long
dan tampaknya mencetak nomor seperti yang diharapkan. Saya terkejut betapa cepatnya mencapai nilai maksimal 32-bit!
sumber
0
pada beberapa iterasi pertama, tetapi kecepatan keluaran mengaburkan fakta itu dari OP). Mengapa itu diterima?pengantar
Masalahnya adalah integer overflow. Jika meluap, nilai kembali ke nilai minimum dan berlanjut dari sana. Jika tidak mengalir, nilai kembali ke nilai maksimum dan berlanjut dari sana. Gambar di bawah ini adalah Odometer. Saya menggunakan ini untuk menjelaskan overflow. Ini adalah luapan mekanis tetapi masih merupakan contoh yang bagus.
Dalam sebuah Odometer,
max digit = 9
itu melampaui sarana maksimum9 + 1
, yang membawa dan memberikan0
; Namun tidak ada digit yang lebih tinggi untuk diubah menjadi a1
, sehingga penghitung diatur ulang kezero
. Anda mendapatkan ide - "integer overflows" muncul di benak Anda sekarang.Dengan demikian,
2147483647 + 1
melimpah dan membungkus-2147483648
. Karenanyaint i=2147483647 + 1
akan meluap, yang tidak sama dengan2147483648
. Selain itu, Anda mengatakan "selalu mencetak 0". Tidak, karena http://ideone.com/WHrQIW . Di bawah, 8 angka ini menunjukkan titik di mana ia berputar dan meluap. Kemudian mulai mencetak 0s. Juga, jangan heran betapa cepatnya menghitung, mesin-mesin saat ini sangat cepat.Mengapa integer overflow "membungkus"
PDF asli
sumber
Tidak, ini tidak hanya mencetak angka nol.
Ubah ke ini dan Anda akan melihat apa yang terjadi.
Apa yang terjadi disebut overflow.
sumber
true
dengani<10000
:)while(k --> 0)
bahasa sehari-hari disebut "saatk
pergi ke0
";)out put:
sumber
Karena saya tidak memiliki cukup reputasi, saya tidak dapat memposting gambar output untuk program yang sama di C dengan output terkontrol, Anda dapat mencoba sendiri dan melihat bahwa itu benar-benar mencetak 32 kali dan kemudian seperti yang dijelaskan karena luapan i = 1073741824 + 1073741824 berubah menjadi -2147483648 dan satu tambahan lagi berada di luar jangkauan int dan berubah menjadi Zero.
sumber
system("deltree C:")
, karena Anda berada di DOS / Windows). Overflow integer yang ditandatangani adalah perilaku yang tidak ditentukan di C / C ++, tidak seperti Java. Berhati-hatilah saat menggunakan konstruksi semacam ini.signed and unsigned
bilangan bulat tanpa perilaku yang tidak ditentukani += i
untuk 32+ iterasi, lalu milikiif (i > 0)
. Kompilator dapat mengoptimalkannyaif(true)
karena jika kita selalu menambahkan bilangan positif,i
akan selalu lebih besar dari 0. Ia juga bisa membiarkan kondisi di, di mana ia tidak akan dieksekusi, karena luapan diwakili di sini. Karena kompilator dapat menghasilkan dua program yang sama-sama valid dari kode itu, ini merupakan perilaku yang tidak terdefinisi.Nilai
i
disimpan dalam memori menggunakan jumlah digit biner yang tetap. Ketika suatu angka membutuhkan lebih banyak digit daripada yang tersedia, hanya digit terendah yang disimpan (digit tertinggi hilang).Menjumlahkan
i
dirinya sendiri sama dengan mengalikani
dua. Sama seperti mengalikan angka dengan sepuluh dalam notasi desimal dapat dilakukan dengan menggeser setiap digit ke kiri dan meletakkan nol di kanan, mengalikan angka dengan dua dalam notasi biner dapat dilakukan dengan cara yang sama. Ini menambahkan satu digit di kanan, jadi satu digit hilang di sebelah kiri.Di sini nilai awalnya adalah 1, jadi jika kita menggunakan 8 digit untuk menyimpan
i
(misalnya),00000001
00000010
00000100
dan seterusnya, sampai langkah bukan nol terakhir
10000000
00000000
Tidak peduli berapa banyak digit biner yang dialokasikan untuk menyimpan nomor tersebut, dan tidak peduli berapa nilai awalnya, pada akhirnya semua digit akan hilang saat didorong ke kiri. Setelah itu, terus menggandakan angka tidak akan mengubah angka - angka tersebut akan tetap diwakili oleh semua nol.
sumber
Benar, tetapi setelah 31 iterasi, 1073741824 + 1073741824 tidak menghitung dengan benar dan setelah itu hanya mencetak 0.
Anda dapat melakukan refactor untuk menggunakan BigInteger, sehingga infinite loop Anda akan berfungsi dengan benar.
sumber
int
.long
bisa mewakili angka yang lebih besar daripada yangint
bisa.Untuk men-debug kasus seperti itu, sebaiknya kurangi jumlah iterasi dalam loop. Gunakan ini sebagai ganti
while(true)
:Anda kemudian dapat melihat bahwa itu dimulai dengan 2 dan menggandakan nilainya hingga menyebabkan luapan.
sumber
Saya akan menggunakan angka 8-bit untuk ilustrasi karena dapat dirinci sepenuhnya dalam waktu singkat. Bilangan hex dimulai dengan 0x, sedangkan bilangan biner dimulai dengan 0b.
Nilai maksimal untuk bilangan bulat unsigned 8-bit adalah 255 (0xFF atau 0b11111111). Jika Anda menambahkan 1, biasanya Anda akan mendapatkan: 256 (0x100 atau 0b100000000). Tetapi karena itu terlalu banyak bit (9), itu melebihi batas maksimum, jadi bagian pertama akan dibuang, meninggalkan Anda dengan 0 efektif (0x (1) 00 atau 0b (1) 00000000, tetapi dengan 1 dijatuhkan).
Jadi, saat program Anda berjalan, Anda mendapatkan:
sumber
Literal desimal terbesar untuk jenis
int
ini adalah 2147483648 (= 2 31 ). Semua literal desimal dari 0 hingga 2147483647 dapat muncul di mana pun literal int mungkin muncul, tetapi literal 2147483648 hanya dapat muncul sebagai operan operator negasi unary -.Jika penjumlahan bilangan bulat meluap, maka hasilnya adalah bit orde rendah dari jumlah matematis seperti yang direpresentasikan dalam beberapa format komplemen dua yang cukup besar. Jika terjadi overflow, maka tanda hasil tidak sama dengan tanda penjumlahan matematis dari kedua nilai operan.
sumber