58

(-0 === 0) が真になることはわかっています。-0 < 0 が発生する理由を知りたいですか?

このコードを stackoverflow 実行コンテキストで実行すると、0.

const arr = [+0, 0, -0];
console.log(Math.min(...arr));

しかし、ブラウザ コンソールで同じコードを実行すると、-0. 何故ですか?私はグーグルで検索しようとしましたが、有用なものは見つかりませんでした。この質問は、誰かの実際の例に価値をもたらさないかもしれません.JSがそれをどのように計算するかを理解したかったのです.

 const arr = [+0, 0, -0];
    console.log(Math.min(...arr)); // -0
4

4 に答える 4

9

この回答のポイントは、Math.min完全に可換であるという言語設計の選択が理にかなっている理由を説明することです。

-0 < 0 が発生する理由を知りたいですか?

そうではありません。<は「最小」とは別の操作であり、 のような IEEE 比較Math.minだけに基づいているわけではありません。<b<a ? b : a

それは可換ではないでしょう。NaN と符号付きゼロ。(<いずれかのオペランドが NaN の場合は false であるため、 が生成されaます)。
最小の驚きの原則に関する限り、それは少なくとも同じくらい驚くべきことです (それ以上ではないにしても)Math.min(-1,NaN)でしNaNたがMath.min(NaN, -1)でした-1.

JS 言語の設計者はMath.minNaN 伝播を望んでいたため、<とにかくそれをベースにすることはできませんでした。 彼らは、符号付きゼロを含めて完全に交換可能にすることを選択しましたが、これは賢明な決定のようです。

OTOH、ほとんどのコードは符号付きゼロを気にしないため、この言語設計の選択は、誰かが明確に定義された符号付きゼロのセマンティクスを必要とするまれなケースに対応するために、誰もが少しパフォーマンスを犠牲にします.

配列内の NaN を無視する単純な操作が必要な場合は、 を繰り返しますcurrent_min = x < current_min ? x : current_min。これはすべての NaN を無視-0し、for current_min <= +0.0(IEEE 比較) も無視します。または、current_minNaN で開始すると、NaN のままになります。これらの多くは関数にとって望ましくないためMath.min、そのようには機能しません。


他の言語を比較すると、C の標準fmin関数は可換 wrt です。NaN (非 NaN がある場合は JS の反対を返す) ですが、可換である必要はありません。ゼロを署名しました。fmin一部の C 実装は、 /に対して +-0.0 に対して JS のように動作することを選択しますfmax

しかし、C++std::min 純粋に<操作の観点から定義されているため、そのように機能します。(文字列などの非数値型を含め、一般的に機能することを意図してstd::fminいます。FP 固有の規則がないのとは異なります。) x86 でブランチレス FP の最小値と最大値を与える命令は何ですか? を参照してください。re: x86 のminps命令と C++std::minはどちらも可換ではありません。NaN および符号付きゼロ。


IEEE 754<では、個別の FP 番号に対する合計順序は示されません。Math.minは NaN を除きます (たとえば、 と を使用してソート ネットワークを構築した場合Math.max)。その順序は と一致しません。Math.maxどちらも NaN があれば NaN を返すため、最小/最大コンパレータを使用するソート ネットワークは、入力配列。

Math.minどの引数が返されたかを確認するようなものなしでは、それだけではソートには十分ではありませんが==、それは NaN だけでなく符号付きゼロでも機能しません。

于 2021-12-23T03:57:55.377 に答える