[解決済み] この「for」ループは停止するのか、その理由と停止しない理由 for (var i=0; 1/i > 0; i++) { }.
質問
これは
for
のループは止まらないのでしょうか?
for (var i=0; 1/i > 0; i++) {
}
もしそうなら、いつ、なぜですか?止まるとは言われましたが、その理由は教えてもらえませんでした。
更新情報
調査の一環として、ボンネットの下で何が起こっているのかをすべて説明する、かなり長くて詳細な記事を書きました。 JavaScript の Number 型について知っておくべきことは、以下のとおりです。
どのように解決するのですか?
(メタコンテンツは苦手ですが gotnullの と le_m の の答えは、どちらも正しくて有用です。それらはもともと、そして もそうですが このコミュニティWikiが投稿された後に行われた編集で、そうなりました。このCWの当初の動機は、これらの編集の結果、ほとんどなくなってしまいましたが、有用であることに変わりはありませんから...。また 著者は数名しかいませんが、他の多くのコミュニティメンバーがコメントを寄せてくれて、それを折り込み、整理してくれています。これは名前だけのCWではありません)。
正しく実装されたJavaScriptエンジンでは、ループは止まりません。 (エンジンのホスト環境では、無限ループのため最終的に終了してしまうかもしれませんが、それは別の話です)。
理由はこうです。
-
当初は
i
は0
という条件であれば1/i > 0
が真になるのは、JavaScriptでは1/0
はInfinity
であり、かつInfinity > 0
は真である。 -
その後に
i
はインクリメントされ、正の整数値として長い時間(さらに 9,007,199,254,740,991 回)成長し続けるでしょう。それらのすべてのケースで1/i
はそのまま> 0
(の値です(ただし1/i
を取得します。 本当に を小さくする!)ので、ループはi
という値になるループまで続きます。Number.MAX_SAFE_INTEGER
. -
JavaScript の数値は IEEE-754 倍精度バイナリ浮動小数点で、かなりコンパクトなフォーマット (64 ビット) ですが、高速な計算と広大な範囲を提供します。これは、符号ビット、11 ビットの指数、52 ビットのシグニフィカントとして数値を格納することで実現されています (ただし、巧妙な方法で実際には 53 ビットの精度を得ています)。これは バイナリ (ベース2)浮動小数点です。シグニフィカンド (およびいくつかの巧妙な処理) が値を与え、指数がその数の大きさを与えます。
当然ながら、これだけ多くの有効ビットがあれば、すべての数を格納できるわけではありません。以下は、数値 1 と、このフォーマットが格納できる 1 の次に大きい数値である 1 + 2 です。 -52 ≈ 1.00000000000000022, そしてその次に大きい数字 1 + 2 × 2 -52 ≈ 1.00000000000000044:
+--------------------------------------------------------------- sign bit / +-------+------------------------------------------------------ exponent / / | +-------------------------------------------------+- シグニフィカント 0 01111111111 0000000000000000000000000000000000000000000000000000 = 1 0 01111111111 0000000000000000000000000000000000000000000000000001 ≈ 1.00000000000000022 0 01111111111 0000000000000000000000000000000000000000000000000010 ≈ 1.00000000000000044
1.00000000000000022から1.00000000000000044にジャンプしていることに注意してください。1.0000000000000003を格納する方法はありません。これは整数でも起こりうることです。
Number.MAX_SAFE_INTEGER
(9,007,199,254,740,991) は、このフォーマットが保持できる正の整数の最大値で、ここでi
とi + 1
はどちらも正確に表現できる ( スペック ). 9,007,199,254,740,991 と 9,007,199,254,740,992 の両方が表現可能であるが 次 9,007,199,254,740,992の次に表現できる整数は9,007,199,254,740,994となります。以下はそのビットパターンです。右端(最下位)のビットに注意してください。+--------------------------------------------------------------- sign bit / +-------+------------------------------------------------------ exponent / / | +-------------------------------------------------+- シグニフィカント 0 10000110011 1111111111111111111111111111111111111111111111111111 = 9007199254740991 (Number.MAX_SAFE_INTEGER) 0 10000110100 0000000000000000000000000000000000000000000000000000 = 9007199254740992 (Number.MAX_SAFE_INTEGER + 1) x xxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。 9007199254740993 (Number.MAX_SAFE_INTEGER + 2) cannot be stored 0 10000110100 0000000000000000000000000000000000000000000000000001 = 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)
この形式は基数2であり、この指数では最下位ビットはもはや小数ではありません。これはループに影響を与えます。
-
を完了した後
i = 9,007,199,254,740,992
のループに入る。i++
は私たちを与える...i = 9,007,199,254,740,992
には何の変化もありません。i
には変化がありません。なぜなら、次の整数を格納することができず、計算が切り捨てになってしまうからです。i
を実行すると、次のように変化します。i += 2
をした場合、しかしi++
は変更できません。つまり定常状態になったわけです。i
は決して変化せず、ループは決して終了しません。
以下、関連する様々な計算を紹介します。
if (!Number.MAX_SAFE_INTEGER) {
// Browser doesn't have the Number.MAX_SAFE_INTEGER
// property; shim it. Should use Object.defineProperty
// but hey, maybe it's so old it doesn't have that either
Number.MAX_SAFE_INTEGER = 9007199254740991;
}
var i = 0;
console.log(i, 1/i, 1/i > 0); // 0, Infinity, true
i++;
console.log(i, 1/i, 1/i > 0); // 1, 1, true
// ...eventually i is incremented all the way to Number.MAX_SAFE_INTEGER
i = Number.MAX_SAFE_INTEGER;
console.log(i, 1/i, 1/i > 0); // 9007199254740991 1.1102230246251568e-16, true
i++;
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true
i++;
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true (no change)
console.log(i == i + 1); // true
関連
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] let "と "var "の使い分けは?
-
[解決済み] なぜGoogleはJSONレスポンスにwhile(1);を前置するのでしょうか?
-
[解決済み] 私のJavaScriptコードは "No 'Access-Control-Allow-Origin' header is present on requested resource "というエラーを受け取りますが、Postmanはそうならないのはなぜですか?
-
[解決済み] URLを新しいタブで開く(新しいウィンドウではない)
-
[解決済み] JSONPとは何か、なぜ作られたのか?
-
[解決済み] 配列の反復処理に "for...in "を使用するのは、なぜ良くないのでしょうか?
-
[解決済み] なぜ ++[[]][+[] +[+[]] は "10" という文字列を返すのでしょうか?
-
[解決済み] varキーワードの目的と、どのような場合に使用する(または省略する)べきですか?
-
[解決済み] jQueryのバージョン1、バージョン2、バージョン3の違いは何ですか?[クローズド]
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] node.jsで文字列のsha1ハッシュを取得するにはどうすればよいですか?
-
[解決済み] React js 親コンポーネントから子コンポーネントの状態を変更する
-
[解決済み] BlobからArrayBufferへ移行する方法
-
[解決済み] jQueryで入力ファイルが空かどうかをチェックする方法
-
[解決済み] JavaScriptで長い配列を小さい配列に分割する方法
-
[解決済み] javascriptでオプションのパラメータを扱う
-
[解決済み] Node.jsのES6クラスをrequireで作る
-
[解決済み] なぜjavascriptのES6 Promisesはresolve後も実行を継続するのですか?
-
[解決済み] javascriptのキャンバスで画像をリサイズする (スムーズ)
-
[解決済み] 変異を伴わないオブジェクトからの値の削除