大きい数字の計算はじめました。

UI開発者 宇賀

朝でも夜でもこんにちは!UI開発者の宇賀です!

気づけばもう5月。最近はすっかり暖かくなりましたね。すでに夏日となった日も多く、むしろ蒸し暑いくらいです...。

前回の記事、思わぬところで学習スイッチが入るかもしれないJavaScriptの小ネタ5選!で紹介した「02. 実は小数点の計算が苦手」というお話はもう読んでいただけましたでしょうか?まだ読んでないよ!という方はまずそちらからご覧いただけるとうれしいです。

さて、5月病にも負けず今回みなさんにお伝えする内容は「JavaScriptで大きい数字を計算する方法が実装される件」についてです。

「大きい数字」とはどれくらいの話かというと、なんと「2の53乗」を超える世界です。実際に計算すると「9007兆1992億5474万0992」という数字になりますが、これはもう私たちが日々日常の中で触れるような「大きい数字」のレベルを超えすぎていて...なんだかピンと来ないですね。

JavaScriptは本来、「9007兆1992億5474万0992」以上の数字を正確に計算することはできません。処理できるのはこの数字から「1」を引いた「9007兆1992億5474万0991」以下の数字で、その理由はIEEE754と呼ばれる標準規格に則って各ベンダーがブラウザに実装をしているからなのですが...このあたりに関する詳しい話はまたの機会にとっておきますね...。

私たち人間からすれば、「2の53乗」以下なら正確に計算できるというだけでも十分すごい感じがしますが、その先の世界へ進むための手段が実装されるとのことなので、さっそく本題に入っていきましょう!

前回の記事で「仮想小数点方式」という考え方とともに「JavaScriptではあまりにも桁数が多い計算は整数でも正確に行うことができない」ことを紹介しましたが、先日公開されたGoogle Developersの記事によると実は、JavaScriptでもこの途方もない数字を安全に計算できる時代がくるそうなのです。

具体的には、Google Chrome 67で実装される「window.BigInt()」という関数で実現することができるようになるとのこと。

このBigIntはChromeだけが実装するわけではなく、Firefoxでも実装が予定されているようで、近々Edgeやその他のブラウザにも実装される話がでてくるかもしれませんね。

本稿ではそんなBigIntの仕様についてもすこしだけ触れてみたいと思います。

さっそく、Canary版Google Chrome(68.02.3415.0 Official Build 64ビット)で動かしてみました。

記事の意冒頭で登場したJavaScriptで扱える最も大きな整数(9007兆~)は「Number.MAX_SAFE_INTEGER」というプロパティに元々格納されています。これは実際にBigIntを利用して計算してみた結果のキャプチャです。

BigIntを利用した結果、無事に正しく計算できました!

返り値をよく見ると、BigIntに渡した数字の返り値は、数字の最後に「n」がついているのが確認できますね。整数リテラルの後に接尾辞「n」を持つ値は、number型ではなくbigInt型であると解釈されます。直接コードの中に「1n」と記述することももちろん可能です。

これまでにない新しいプリミティブ型であるbigint型が、既存の仕様とどのような関わり方をするのかもいくつか見ていきましょう。

BigIntと値の比較

bigint型の値とnumber型の値を比較する際、整数値が同一の時、厳密な比較(===)ではfalseを返しますが、型変換を伴う比較(==)ではtrueを返します。bigint型にそろえてから厳密な比較を行うとより安全でしょう。

前回の記事でtruthyな値、falsyな値についても紹介しましたが、bigint型もnumber型同様整数部分が「0」である場合のみfalsyな値として解釈され、整数部分が負の値であった場合にもtruthyな値として解釈されます。

BigIntとJSON

もしJSON周りでbigint型の値を利用する場合は注意が必要です。JSONはbigint型の値に対応していません。

function型は削除されたり、NaNはnullに変換されたりしますが、bigint型は特別な処理がされずTypeErrorを引き起こすようです。

JSON.stringifyを必要とする処理の中でbiging型が必要な場合は、一時的に文字列に変換すると良いかもしれないですね。

bigint型の値を含むオブジェクトをJSONに変換し、再びオブジェクトへ戻す例

終わりに

ここまでBigIntに入れる値が整数なのかどうかという検証をスキップして実行例をご紹介してきましたが、BigIntはその名の通り整数値のみ受け取ることができる関数です。誤ってBigIntの引数に小数を渡してしまうとRangeErrorを引き起こします。もし少数含む計算の中でbigint型を必要とする値を比較する際は、注意が必要です。

BigIntのより詳細な詳しい情報は、前半に掲載されているツイートや、BigInt: arbitrary-precision integers in JavaScriptなどをご覧いただければと思います。

今回のように他の言語ではできてJavaScriptではできなかったことが1つ1つ解決されていくのを見ていると、未来がとても楽しみですね。今後も目が離せません。

今回もこの記事が面白かった!と思った方はTwtterやFacebookなど、ぜひぜひシェアしていただければと思います!

次回もお楽しみに!