符 号 部 | 指数部 exponent 8 | 仮数部 fraction 23 | |||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
符 号 部 | 指数部 11 | 仮数部 52 (うち20) | |||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
仮数部 52 (うち32) | |||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
浮動小数点数(IEEE754)の内部表現をシミュレートします。
IPAの情報処理試験の勉強用としてと、JavaScriptで小数の計算の誤差が なぜ発生するのかきちんと理解したかったので作成しました。 おかげで「0.1 + 0.2」がなぜ0.3にならないのかが、ビット単位で把握できました。
丸め方式の1つに、丸める前の実数と距離的に最も近い数に丸める、 RN (Round toNearest)方式があります。 m進数で「m/2-1捨m/2入」、10進数だと四捨五入、2進数だと0捨1入になります。 誤差をできるだけ小さくする方法として利用されます。
ただしIEEE754のRN方式は偶数丸めと呼ばれる、2つの桁を使って判断する方法を採用しています。 「00」→「00」、「01」→「00」、「10」→「10」、「11」→「100」。
0.1と0.2は1桁異なる値であり、かつ どちらも仮数部の最下位ビットが繰り上がった値になります。 その結果0.1と0.2を足すと、0.3より少し大きい値になってしまうのです。
もともとは、「数値リテラル→内部表現」「内部表現→数値リテラル」どちらの機能も、自力で計算していました。 しかしJavaScriptの機能だけで実装しようとすると限界があり、極端に大きい値や極端に0に近い値などで正しく表現できない不具合が発生していました。
しかしJavaScriptでも生のバイナリーデータにアクセスする機能が追加され、 新しい機能に非対応なブラウザの代表だったIEがサポート終了となり、 Web環境でもJavaScriptの新しい機能を問題なく使えるようになってきたため、 2022/9にArrayBuffer, DataViewを使用した実装に切り替えました。
現在のところ不具合は見つかっていません。 しかし荒削りな実装なため不具合があるかもしれません。 もしも不具合を発見した場合にはご連絡お願いします。
このページに関するちょっとした感想または、要望、バグ・間違いの指摘などは、下記の送信欄からお送りください。 質問・その他お問合せなど、返信をご希望の方は「こちらのページ」からメッセージをお送りください。
「このページはお役に立ちましたか?」のアンケートと自由メッセージのどちらか一方でかまいません (両方だとよりうれしいです)。お気軽にご利用ください (感想・どんな用途で使用したかなどをいただけると作成・運営の励みになります!)。