Stoppt diese for
Schleife jemals?
for (var i=0; 1/i > 0; i++) {
}
Wenn ja, wann und warum? Mir wurde gesagt, dass es aufhört, aber mir wurde kein Grund dafür gegeben.
Upddate
Als Teil der Untersuchung habe ich einen ziemlich langen und detaillierten Artikel geschrieben, der alles erklärt, was unter der Haube vor sich geht. Hier ist, was Sie über den Zahlentyp von JavaScript wissen müssen
javascript
Max Koretskyi
quelle
quelle
Number.MAX_SAFE_INTEGER + 1
.Antworten:
(Ich bin kein Fan von Meta-Inhalten, aber: Die Antworten von gotnull und le_m sind korrekt und nützlich. Sie waren ursprünglich und noch mehr mit den Änderungen, die nach der Veröffentlichung dieses Community-Wikis vorgenommen wurden. Die ursprüngliche Motivation für dieses CW ist aufgrund dieser Änderungen größtenteils verschwunden, aber es bleibt nützlich, also ... Auch: Während nur ein paar Autoren aufgelistet sind, haben viele andere Community-Mitglieder bei Kommentaren, die eingeklappt und bereinigt wurden, sehr geholfen ist nicht nur ein CW im Namen.)
Die Schleife wird in einer korrekt implementierten JavaScript-Engine nicht gestoppt. (Die Host-Umgebung der Engine beendet sie möglicherweise, weil sie endlos ist, aber das ist eine andere Sache.)
Hier ist der Grund:
Wenn dies der Fall
i
ist0
, ist die Bedingung zunächst1/i > 0
wahr, da in JavaScript1/0
istInfinity
undInfinity > 0
wahr ist.Danach
i
wird es erhöht und wächst noch lange als positiver ganzzahliger Wert weiter (weitere 9.007.199.254.740.991 Iterationen). In allen diesen Fällen1/i
bleibt> 0
(auch wenn die Werte für1/i
bekommen wirklich gegen Ende klein!) Und so die Schleife bis einschließlich der Schleife weiter , woi
der Wert erreichtNumber.MAX_SAFE_INTEGER
.Zahlen in JavaScript sind binäre Gleitkommazahlen mit doppelter Genauigkeit nach IEEE-754, ein ziemlich kompaktes Format (64 Bit), das schnelle Berechnungen und einen großen Bereich ermöglicht. Dazu wird die Zahl als Vorzeichenbit, 11-Bit-Exponent und 52-Bit-Signifikand gespeichert (obwohl sie durch Cleverness tatsächlich 53 Bit Genauigkeit erhält). Es ist ein binärer Gleitkomma (Basis 2): Der Signifikand (plus etwas Klugheit) gibt uns den Wert und der Exponent gibt uns die Größe der Zahl.
Natürlich kann mit nur so vielen signifikanten Bits nicht jede Zahl gespeichert werden. Hier ist die Zahl 1 und die nächsthöhere Zahl nach 1, die das Format speichern kann, 1 + 2 -52 ≈ 1.00000000000000022 und die nächsthöhere Zahl danach 1 + 2 × 2 -52 ≈ 1.00000000000000044:
Beachten Sie den Sprung von 1.00000000000000022 auf 1.00000000000000044; Es gibt keine Möglichkeit, 1.0000000000000003 zu speichern. Das kann mit ganzen Zahlen passieren, auch:
Number.MAX_SAFE_INTEGER
(9,007,199,254,740,991) ist die höchste positive Zahl , dass das Format halten kann , woi
undi + 1
sind beide exakt darstellbar ( spec ). Sowohl 9.007.199.254.740.991 als auch 9.007.199.254.740.992 können dargestellt werden, die nächste Ganzzahl, 9.007.199.254.740.993, jedoch nicht. Die nächste Ganzzahl, die wir nach 9.007.199.254.740.992 darstellen können, ist 9.007.199.254.740.994. Hier sind die Bitmuster. Beachten Sie das Bit ganz rechts (niedrigstwertig):Denken Sie daran, dass das Format Basis 2 ist und mit diesem Exponenten das niedrigstwertige Bit nicht mehr gebrochen ist. es hat einen Wert von 2. Es kann aus (9.007.199.254.740.992) oder ein (9.007.199.254.740.994) sein; Zu diesem Zeitpunkt haben wir begonnen, die Genauigkeit selbst auf der ganzen Zahlenskala (Ganzzahlskala) zu verlieren. Was Auswirkungen auf unsere Schleife hat!
Nach Abschluss der
i = 9,007,199,254,740,992
Schleifei++
gibt uns ...i = 9,007,199,254,740,992
wieder; Es gibt keine Änderung ini
, da die nächste Ganzzahl nicht gespeichert werden kann und die Berechnung abgerundet wird.i
würde sich ändern, wenn wir es tun würdeni += 2
,i++
kann es aber nicht ändern. Wir haben also den stationären Zustand erreicht:i
Ändert sich nie und die Schleife endet nie.Hier sind die verschiedenen relevanten Berechnungen:
quelle
Antworten:
Die Bedingung
1/i > 0
wird immer als wahr bewertet:Anfangs ist es wahr, weil es
1/0
bewertetInfinity
undInfinity > 0
wahr istEs bleibt wahr, da
1/i > 0
es für alle gilti < Infinity
undi++
nie erreichtInfinity
.Warum erreicht
i++
nieInfinity
? Aufgrund der begrenzten Genauigkeit desNumber
Datentyps gibt es einen Wert, für deni + 1 == i
:Sobald
i
dieser Wert erreicht ist (der entspricht ), bleibt er auch danach gleich .Number.MAX_SAFE_INTEGER
+ 1
i++
Wir haben also eine Endlosschleife.
Blinddarm:
Warum ist
9007199254740992 + 1 == 9007199254740992
?Der
Number
Datentyp von JavaScript ist ein 64-Bit- Float mit doppelter Genauigkeit nach IEEE 754 . JedesNumber
wird zerlegt und als drei Teile gespeichert: 1-Bit-Vorzeichen, 11-Bit-Exponent und 52-Bit-Mantisse. Sein Wert ist -1 Vorzeichen × Mantisse × 2 Exponent .Wie ist 9007199254740992 dargestellt? Als 1,0 × 2 53 oder binär:
Wenn wir das niedrigstwertige Bit der Mantisse erhöhen, erhalten wir die nächsthöhere Zahl:
Der Wert dieser Nummer ist 1.00000000000000022… × 2 53 = 9007199254740994
Was bedeutet das?
Number
kann entweder 900719925474099 2 oder 900719925474099 4 sein , aber nichts dazwischen.Welches sollen wir nun wählen, um 900719925474099 2 + 1 darzustellen ? Die Rundungsregeln nach IEEE 754 geben die Antwort: 900719925474099 2 .
quelle
for (var i = 0; i < Infinity; i += 1E306);
. Aber ich komme dahin, woher du kommst;)Die
Number.MAX_SAFE_INTEGER
Konstante repräsentiert die maximale sichere Ganzzahl in JavaScript. DieMAX_SAFE_INTEGER
Konstante hat einen Wert von9007199254740991
. Der Grund für diese Zahl ist, dass JavaScript Gleitkomma-Zahlen mit doppelter Genauigkeit verwendet, wie in IEEE 754 angegeben, und nur Zahlen zwischen - (2 53 - 1) und 2 53 - 1 sicher darstellen kann .Sicher bezieht sich in diesem Zusammenhang auf die Fähigkeit, Ganzzahlen genau darzustellen und korrekt zu vergleichen. Zum Beispiel
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2
wird ausgewertettrue
, was mathematisch falsch ist. SieheNumber.isSafeInteger()
für weitere Informationen.Da
MAX_SAFE_INTEGER
es sich um eine statische Eigenschaft von handeltNumber
, verwenden Sie sie immer alsNumber.MAX_SAFE_INTEGER
und nicht als Eigenschaft eines vonNumber
Ihnen erstellten Objekts.AKTUALISIEREN:
Jemand in einer Antwort, die gelöscht wurde, erwähnte:
i
wird niemals unendlich erreichen. Sobald es erreicht istNumber.MAX_SAFE_INTEGER
,i++
wird die Variable nicht mehr erhöht. Dies ist in der Tat nicht korrekt.@TJ Crowder kommentiert das
i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;
heißtfalse
. Die nächste Iteration erreicht jedoch einen unveränderlichen Zustand, sodass die Hauptantwort richtig ist.i
im Beispiel nie erreichtInfinity
.quelle
9007199254740992 + 1
ist9007199254740992
.for (var i=0; NaN > 0; i++) { console.log(i); }
wird nichts produzieren.1/i > 0
) würde falsch sein, denn wenni
ist0
,1/i
istNaN
, undNaN > 0
ist falsch.