UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【JavaScript】NaNの話

以下の記事が話題になった

nmi.jp

  • NaN === NaNfalse である
  • console.log(NaN == false); // → false
  • グローバルオブジェクトにあるisNaNNumber.isNaNは挙動が違う
  • 配列のindexOfNaNは見つけられない

ということさえ覚えておけばよさそうで、あとはやろうと思えばNaN === NaNをboolean以外にもできる(まぁやらないよね)っていう話だった

ところで

このブログの中の余談1にあったNaNのビット表現を説明する箇所で、以下の検証コードを挙げられていたが、自分の知識不足で何をしているのかがわからなかった

f:id:uggds:20210919150822p:plain

なので、ここを理解するようにする

Float64ArrayとかUint8Arrayとか

Float64ArrayArrayBufferに格納されたバイト配列の各8バイトを浮動小数点としてみなすというもの

次にUint8ArrayArrayBufferに格納されたバイト配列の各1バイトを0 から 255までの値としてみなすというもの

例えば、new ArrayBuffer(16)の場合、Float64ArrayUint8Arrayの関係は以下のようになっている

f:id:uggds:20210919153957p:plain

コードを読み解く

最初にFloat64Arrayのコンストラクタ引数に1を指定しているので8バイトの浮動小数点がはいるよと宣言しており

そこにNaNを代入し、Uint8Arrayで宣言した各1バイトをみると

console.log(charView.join(',')); // → 0,0,0,0,0,0,248,127のようになっている

トルエンディアンなので、逆から並べてビット表現をみると次の図の(1)のようになる

f:id:uggds:20210919164138p:plain

このとき、charView[6] = 0xf0;をした場合(図の(2))では指数部のビットがすべて 1 のままだが、仮数部が全て0なのでInfinityになる

次に、charView[6] = 0xf4;をした場合(図の(3))は指数部のビットがすべて 1 のままで、仮数部が全て0ではないのでNaNになる

このように、NaNは複数通りのビット表現を持つことが許されている

ちなみに、理由はそういう仕様だから

という説明をしていたことが理解できた

他参考記事

https://tc39.es/ecma262/#sec-islooselyequal

https://yosuke-furukawa.hatenablog.com/entry/2018/01/30/174425