ECMASCript2015 Language Specificationの一人輪読会資料。
前回までは翻訳メモみたいなのをペタッと貼っただけでしたが、今回からやり方をちょっと変えて、
翻訳メモはGithubのリポジトリ(雑な訳が多いですが。。。)にpushし、Qiitaの方には理解する上で調べたことをまとめるようにした。
今回は、6.1.6のNumber型についてまとめた。
Number型については、ECMASCript5からほとんど(というかまったく?)変更がないようだが、浮動小数点数についてかなり忘れていたので、調べた。
浮動小数点数のおさらい
ECMAScriptのNumber型は、IEEE754-2008(IEEE浮動小数点数演算標準; IEEE Standard for Floating-Point Arithmetic)で定義されている64ビット倍精度の浮動小数点数を表現している。
6.1.6のNUmber型の説明はほとんどIEEE754の説明なので、改めて浮動小数点数について復習した。
- 浮動小数点数は、数値の正負を表す符号部、仮数部、指数部で数値を表現する。
- 符号部をs(1か-1)、仮数部をm、指数部をeとすると、「s * m * 2のe乗」が表現される数値
- 64ビット倍精度の場合、符号部が1ビット、指数部が11ビット、仮数部が52ビット
- 符号部は、数値の正負を表す1ビット。0の場合は1、1の場合は-1
- 指数部は、実際の指数に1023足した値が入る。
- 全てのビットが0、または全てのビットが1の場合は、特別な意味を持つので、その2つを除いた1023 〜 -1022の指数が表現可能
- IEEEでは仮数部を1以上2未満に揃えるという決まりがある
- 例)2.5を倍精度で表現
- 2進数にすると10.1なので、そのままだと、仮数が10.1で指数が0(10.1 * 2の0乗)
- 仮数を1以上2未満に揃えると、仮数を1.01で指数が1になる(1.01 * 2の1乗)
- このように仮数の桁を揃えることを 浮動小数点数の正規化 というらしい
- 仮数を1以上2未満に揃えると先頭が必ず1になるので、仮数部では先頭の1を省略して、小数点以下の桁だけが入る
- これをケチ表現(economized form)というらしい
値の種類と個数
値の種類は以下の5種類。
- NaN
- Not a Number
- 指数部の全てのビットが1で、かつ、仮数部が0以外の場合はNaN値
- なので、NaN値は2の52乗 - 2個存在するが、それぞれを区別できるかは実装依存
- ECMAScriptでは、それぞれのNaN値は区別が付かない
- ECMAScriptプログラム中では
NaN
によって生成される
- 無限大
- 指数部の全てのビットが1で、かつ、仮数部が0の場合は無限大値
- 符号部は任意なので、正の無限大値と負の無限大値の2つがある
- ECMAScriptプログラム中では
+Infinity
(または単にInfinity
)と-Infinity
で生成される
上の2つ以外は、有限数(a finite number)
- ゼロ
- 指数部、仮数部共に0の場合は、ゼロ
- 符号部は任意なので、正のゼロと負のゼロが存在する
- ECMAScriptプログラム中では
+0
(または単に0
)と-0
で生成される
- 正規化数
- 指数部が1〜2046(実際の指数で1023 〜 -1022)の場合は、正規化数
- 符号部をs、仮数をm、指数をeとすると
-1 * s * m * Math.pow(2, e)
- 非正規化数
- 指数部が0で仮数部が0以外の場合は、非正規化数
- 正規化数では表現できない、限りなく0に近い、小さい値を表現する
- 仮数部は正規化されていない数値が入る
- 0.000010101であれば、「000010101」
- 指数は-1022で固定なので、
-1 * s * m * Math.pow(2, -1022)
ECMAScript5の日本語訳に載っていた表が分かりやすかったので、載せておきます。
種類 | 符号(1bit) | 指数部(11bit) | 仮数部(52bit) | 値の個数 | |
---|---|---|---|---|---|
NaN | - | 任意 | 2047 | 0以外 | 2^1 * 1 * (2^52-1) = 2^53-2 |
無限大 | - | 任意 | 2047 | 0 | 2^1 * 1 * 1 = 2 |
有限数 | ゼロ | 任意 | 0 | 0 | 2^1 * 1 * 1 = 2 |
正規化数 | 任意 | 1 〜 2046 | 任意 | 2^1 * (2^11-2) * 2^52 = 2^64-2^54 | |
非正規化数 | 任意 | 0 | 0以外 | 2^1 * (2^52-1) * = 2^53-2 |
全部合わせると(NaN値は1個でカウント)、6.1.2の始めに書いてある「18437736874454810627個(2の64乗 - 2の53乗 + 3)」になる。
丸めのルール
0でない実在の数学的な量をNumber型で表現する場合、以下のルールでNumber型の数値が選ばれる。
- 全ての有限数から-0を外して、2の1024乗と2の1024乗 * -1を加えた集合から最も近いものを選択する
- 最も近い値が2つある場合は、偶数の方が選ばれる
- 2の1024乗に近い場合は正の無限大、2の-1024乗に近い場合は負の無限大
- 0が最も近い場合で、その数値が0よりも小さい場合は-0
- それ以外の場合は、そのままの値が使われる
上記のようなロジックは、IEEE754の「再近接丸め(偶数)モード」というらしい。
ECMASCript5では「"round to nearest" mode」だが、ECMAScript2015では「"round to nearest, ties to even" mode」になっているが、何か違うのだろうか。。誰か知っていたら教えてください。
次はSymbolのウェルノウンであまり知られていないやつとかについて調べてまとめようかなー。