Apakah for
putaran ini pernah berhenti?
for (var i=0; 1/i > 0; i++) {
}
Jika ya, kapan dan mengapa? Saya diberitahu bahwa itu berhenti, tetapi saya tidak diberi alasan untuk itu.
Pembaruan
Sebagai bagian dari investigasi, saya telah menulis artikel yang cukup panjang dan mendetail yang menjelaskan semua yang terjadi di balik terpal - Inilah yang perlu Anda ketahui tentang jenis Nomor JavaScript
javascript
Max Koretskyi
sumber
sumber
Number.MAX_SAFE_INTEGER + 1
.Jawaban:
(Saya bukan penggemar meta-konten, tapi: jawaban gotnull dan le_m sama-sama benar dan berguna. Awalnya, dan terlebih lagi dengan pengeditan yang dilakukan setelah Wiki Komunitas ini diposting. Motivasi asli untuk CW ini sebagian besar hilang sebagai akibat dari pengeditan tersebut, tetapi tetap berguna, jadi ... Juga: Meskipun hanya ada beberapa penulis yang terdaftar, banyak anggota komunitas lainnya telah sangat membantu dengan komentar yang telah dimasukkan dan dibersihkan. bukan hanya CW dalam nama.)
Perulangan tidak akan berhenti di mesin JavaScript yang diterapkan dengan benar. (Lingkungan host mesin pada akhirnya dapat menghentikannya karena tidak ada habisnya, tetapi itu adalah hal lain.)
Inilah alasannya:
Awalnya, when
i
is0
, kondisinya1/i > 0
benar karena dalam JavaScript,1/0
isInfinity
, danInfinity > 0
true.Setelah itu,
i
akan bertambah dan terus bertambah sebagai nilai integer positif untuk waktu yang lama (iterasi selanjutnya 9.007.199.254.740.991). Dalam semua kasus tersebut,1/i
akan tetap> 0
(meskipun nilai untuk1/i
menjadi sangat kecil menjelang akhir!) Dan loop berlanjut ke dan termasuk loop di manai
mencapai nilaiNumber.MAX_SAFE_INTEGER
.Angka dalam JavaScript adalah titik mengambang biner presisi ganda IEEE-754, format yang cukup ringkas (64 bit) yang menyediakan penghitungan cepat dan jangkauan yang luas. Ini dilakukan dengan menyimpan angka sebagai bit tanda, eksponen 11-bit, dan signifikansi 52-bit (meskipun melalui kepintaran itu sebenarnya mendapat presisi 53 bit). Ini adalah titik mengambang biner (basis 2): Signifikan (ditambah beberapa kepintaran) memberi kita nilai, dan eksponen memberi kita besarnya angka tersebut.
Secara alami, dengan begitu banyak bit yang signifikan, tidak setiap nomor dapat disimpan. Berikut adalah angka 1, dan angka tertinggi berikutnya setelah 1 yang dapat disimpan oleh format, 1 + 2 -52 ≈ 1,00000000000000022, dan tertinggi berikutnya setelah itu 1 + 2 × 2 -52 ≈ 1,00000000000000044:
Perhatikan lompatan dari 1.00000000000000022 ke 1.00000000000000044; tidak ada cara untuk menyimpan 1.0000000000000003. Itu juga bisa terjadi dengan bilangan bulat:
Number.MAX_SAFE_INTEGER
(9,007,199,254,740,991) adalah nilai bilangan bulat positif tertinggi yang dapat disimpan oleh format di manai
dani + 1
keduanya dapat direpresentasikan secara tepat ( spesifikasi ). Baik 9.007.199.254.740.991 dan 9.007.199.254.740.992 dapat direpresentasikan, tetapi bilangan bulat berikutnya , 9.007.199.254.740.993, tidak dapat; bilangan bulat berikutnya yang dapat kita wakili setelah 9.007.199.254.740.992 adalah 9.007.199.254.740.994. Berikut adalah pola bitnya, perhatikan bit paling kanan (paling tidak signifikan):Ingat, formatnya adalah basis 2, dan dengan eksponen tersebut bit yang paling tidak signifikan tidak lagi pecahan; itu memiliki nilai 2. Bisa off (9,007,199,254,740,992) atau pada (9,007,199,254,740,994); jadi pada titik ini, kita mulai kehilangan presisi bahkan pada skala bilangan bulat (integer). Yang berimplikasi pada loop kami!
Setelah menyelesaikan
i = 9,007,199,254,740,992
perulangan,i++
berikan kami ...i = 9,007,199,254,740,992
lagi; tidak ada perubahani
, karena bilangan bulat berikutnya tidak dapat disimpan dan kalkulasi berakhir dengan pembulatan ke bawah.i
akan berubah jika kita melakukannyai += 2
, tetapii++
tidak dapat mengubahnya. Jadi kita telah mencapai kondisi mapan:i
tidak pernah berubah, dan loop tidak pernah berhenti.Berikut berbagai perhitungan yang relevan:
sumber
Menjawab:
Ketentuan
1/i > 0
akan selalu bernilai benar:Awalnya ini benar karena
1/0
mengevaluasi keInfinity
danInfinity > 0
benarItu tetap benar karena
1/i > 0
benar untuk semuai < Infinity
dani++
tidak pernah mencapaiInfinity
.Mengapa tidak
i++
pernah mencapaiInfinity
? Karena ketepatanNumber
tipe data yang terbatas , ada nilai yangi + 1 == i
:Setelah
i
mencapai nilai itu (yang sesuai dengan ), nilainya akan tetap sama bahkan setelahnya .Number.MAX_SAFE_INTEGER
+ 1
i++
Oleh karena itu kami memiliki loop tak terbatas.
Lampiran:
Mengapa
9007199254740992 + 1 == 9007199254740992
?Jenis
Number
data JavaScript sebenarnya adalah pelampung presisi ganda IEEE 754 64-bit . MasingNumber
- masing dibongkar dan disimpan sebagai tiga bagian: tanda 1-bit, eksponen 11-bit, dan mantissa 52-bit. Nilainya adalah -1 tanda × mantissa × 2 eksponen .Bagaimana 9007199254740992 direpresentasikan? Sebagai 1.0 × 2 53 , atau dalam biner:
Dengan menambah sedikit mantissa yang paling tidak signifikan, kita mendapatkan angka berikutnya yang lebih tinggi:
Nilai angka itu adalah 1.00000000000000022… × 2 53 = 9007199254740994
Apa artinya?
Number
dapat berupa 900719925474099 2 atau 900719925474099 4 , tetapi tidak ada di antaranya.Sekarang, yang mana yang akan kita pilih untuk mewakili 900719925474099 2 + 1 ? The IEEE 754 pembulatan aturan memberikan jawaban: 900719925474099 2 .
sumber
for (var i = 0; i < Infinity; i += 1E306);
. Tapi saya mengerti dari mana Anda berasal;)The
Number.MAX_SAFE_INTEGER
konstan mewakili bilangan bulat aman maksimum dalam JavaScript. TheMAX_SAFE_INTEGER
konstan memiliki nilai9007199254740991
. Alasan di balik angka itu adalah bahwa JavaScript menggunakan angka format floating-point presisi ganda seperti yang ditentukan dalam IEEE 754 dan hanya dapat mewakili angka dengan aman antara - (2 53 - 1) dan 2 53 - 1.Aman dalam konteks ini mengacu pada kemampuan untuk merepresentasikan bilangan bulat dengan tepat dan membandingkannya dengan benar. Misalnya,
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2
akan mengevaluasi ketrue
, yang secara matematis salah. LihatNumber.isSafeInteger()
untuk informasi lebih lanjut.Karena
MAX_SAFE_INTEGER
merupakan properti statisNumber
, Anda selalu menggunakannya sebagaiNumber.MAX_SAFE_INTEGER
, bukan sebagai propertiNumber
objek yang Anda buat.MEMPERBARUI:
Seseorang dalam jawaban yang dihapus menyebutkan:
i
tidak akan pernah mencapai tak terhingga. Setelah tercapaiNumber.MAX_SAFE_INTEGER
,i++
jangan menaikkan variabel lagi. Ini sebenarnya tidak benar.@TJ Crowder komentar bahwa
i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;
adalahfalse
. Tetapi iterasi berikutnya mencapai keadaan tidak berubah, jadi jawaban utama benar.i
dalam contoh tidak pernah tercapaiInfinity
.sumber
9007199254740992 + 1
adalah9007199254740992
.for (var i=0; NaN > 0; i++) { console.log(i); }
tidak akan menghasilkan apa-apa.1/i > 0
) akan menjadi salah, karena jikai
adalah0
,1/i
adalahNaN
, danNaN > 0
salah.