現代のJavaScriptでは、2種類の数値があります。
-
JavaScriptの正規の数値は、64ビットフォーマットのIEEE-754で保存され、「倍精度浮動小数点数」としても知られています。
-
任意の長さの整数を表すBigIntの数字です。 通常の数値は
253
-253
を下回ることもできないため、必要とされることがあります。
さて、ここでは正規の数について説明します。
数字を書くためのその他の方法
たとえば、10 億と書く必要があるとします。
let billion = 1000000000;
また、セパレーターとしてアンダースコア _
を使うこともできます。
let billion = 1_000_000_000;
ここでアンダースコア _
は「構文糖」の役割を果たしており、数字をより読みやすくしています。 JavaScriptエンジンは、数字の間の_
を単純に無視するので、上記とまったく同じ10億という数字になります。
実際の生活では、長いゼロの連続を書かないようにしています。 そのためにはあまりにも怠惰なのです。 10億なら"1bn"
"7.3bn"
のように書くようにしています。 ほとんどの大きな数字についても同じことが言えます。
JavaScriptでは、数字に"e"
という文字を付けて、ゼロの数を指定することで、数字を短くすることができます。
let billion = 1e9; // 1 billion, literally: 1 and 9 zeroesalert( 7.3e9 ); // 7.3 billions (same as 7300000000 or 7_300_000_000)
つまり、e
1
を掛け合わせます。
1e3 = 1 * 1000 // e3 means *10001.23e6 = 1.23 * 1000000 // e6 means *1000000
さて、とても小さなものを書いてみましょう。 例えば、1マイクロ秒(100万分の1秒):
let ms = 0.000001;
先ほどと同じように、"e"
を使うと便利です。 もし、ゼロを明示的に書かないようにしたいのであれば、次のように言うことができます:
let ms = 1e-6; // six zeroes to the left from 1
0.000001
1e-6
となります。
つまり、"e"
の後の負の数は、与えられた数の0で1で割ることを意味しています。
// -3 divides by 1 with 3 zeroes1e-3 = 1 / 1000 (=0.001)// -6 divides by 1 with 6 zeroes1.23e-6 = 1.23 / 1000000 (=0.00000123)
Hex、2進数、8進数
JavaScriptでは、色の表現や文字のエンコードなど、さまざまな場面でHexadecimal numberが広く使われています。 そのため、当然、より短い書き方が存在します。 0x
の後に数字を記述します。
たとえば、次のようになります。
alert( 0xff ); // 255alert( 0xFF ); // 255 (the same, case doesn't matter)
2進法や8進法の数字はほとんど使われません。 しかし、0b
0o
という接頭辞を使ってサポートされています。
let a; // binary form of 255let b = 0o377; // octal form of 255alert( a == b ); // true, the same number 255 at both sides
このようなサポートをしている数字系は3つしかありません。 他の数字系については、parseInt
という関数を使用する必要があります(この章の後半で紹介します)。
toString(base)
メソッド num.toString(base)
base
num
の文字列表現を返します。
例えばこんな感じです。
let num = 255;alert( num.toString(16) ); // ffalert( num.toString(2) ); // 11111111
base
2
36
までさまざまです。
一般的な使用例は以下のとおりです。
-
base=16は、16進数の色や文字コードなどに使用され、数字は
0..9
A..F
となります。 -
base=2 は主にビット演算のデバッグ用で、数字は
0
1
になります。 -
base=36が最大の場合、数字は
0..9
A..Z
36
の便利なケースは、長い数字の識別子を短いものに変える必要がある場合です、例えば、短いURLを作るために。 この場合、ベースとなる36
を使って、単純に数字で表現することができます。alert( 123456..toString(36) ); // 2n9c
2つの ドットでメソッドを呼び出す123456..toString(36)
toString
..
を配置する必要があります。1つのドットを配置した場合。
123456.toString(36)
のようにドットを1つ置いた場合、JavaScriptの構文では最初のドットの後に小数部があるため、エラーが発生します。また、
(123456).toString(36)
と書くこともできます。丸め
数字を扱うときに最もよく使われる操作の1つが丸めです。
丸めにはいくつかの組み込み関数があります。
3.1
3
-1.1
-2
Math.ceil
3.1
4
-1.1
-1
Math.round
3.1
3.6
4
3.5
4
Math.trunc
(Internet Explorerではサポートされていません) 小数点以下を丸めずに削除します。3.1
3
-1.1
-1
になります。ここで、両者の違いを表にまとめてみました。
Math.floor
Math.ceil
Math.round
Math.trunc
3.1
3
4
3
3
3.6
3
4
4
3
-1.1
-2
td-1
-1
-1
-1.6
-2
-1
-2
-1
これらの関数は、数値の小数部分を処理するために可能なすべての方法をカバーしています。
例えば、
1.2345
1.23
しかできないとします。2つの方法があります。
-
Multiply-and-divide(乗除算)
たとえば、数字を小数点以下2桁に丸めるには、
100
(または10の大きな累乗)を掛けて丸め関数を呼び出し、それを割り戻します。let num = 1.23456;alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23
-
toFixed(n)メソッドは、数値を
n
桁まで丸め、結果を文字列で返します。let num = 12.34;alert( num.toFixed(1) ); // "12.3"
Math.round
と同様に、最も近い値に切り上げたり切り下げたりします。let num = 12.36;alert( num.toFixed(1) ); // "12.4"
toFixed
の結果は文字列であることに注意してください。 小数部が必要以上に短い場合は、最後にゼロが追加されます:let num = 12.34;alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits
単項のプラスや
Number()
+num.toFixed(5)
.不正確な計算
内部的には、数字は64ビットフォーマットのIEEE-754で表現されているので、数字を格納するためのビットはちょうど64ビットあります:52ビットは数字を格納するために使用され、11ビットは小数点の位置を格納します(整数の場合は0です)、1ビットは符号です。
数字が大きすぎると、64 ビットのストレージをオーバーフローしてしまい、無限大になる可能性があります。
次の (falsy!) テストを考えてみてください。)テストを考えてみましょう。
alert( 0.1 + 0.2 == 0.3 ); // false
その通りです。
0.1
0.2
0.3
false
となります。奇遇ですね。
alert( 0.1 + 0.2 ); // 0.30000000000000004
痛っ! ここでは、間違った比較よりももっと多くの結果があります。 あなたが電子商取引のサイトを作っていて、訪問者が
$0.10
$0.20
$0.30000000000000004
となります。しかし、なぜこのようなことが起こるのでしょうか?
数字は、1と0のビット列である2進法でメモリに保存されます。
つまり、
0.1
0.2
1/10
1/3
となります。従って、累乗での除算
10
3
2
1/10
は果てしない 2 進法の分数になってしまいます。2 進法で正確な 0.1 や正確な 0.2 を格納する方法がないのと同様に、10 進法で 3 分の 1 を格納する方法もありません。
数値フォーマット IEEE-754 では、可能な限り近い数値に丸めることでこれを解決しています。
これを実際に見てみましょう。
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
そして、2つの数字を合計すると、その「精度の低下」が加算されます。
これが、
0.1 + 0.2
0.3
ではない理由です。JavaScriptだけではありません同じ問題が他の多くのプログラミング言語にもあります。
PHP、Java、C、Perl、Ruby は、同じ数値フォーマットに基づいているため、まったく同じ結果になります。
この問題を回避することはできるでしょうか。
let sum = 0.1 + 0.2;alert( sum.toFixed(2) ); // 0.30
toFixed
$0.30
を表示する必要がある場合には、実際に便利です。let sum = 0.1 + 0.2;alert( +sum.toFixed(2) ); // 0.3
また、一時的に100倍(またはもっと大きな数字)にして整数にし、計算をしてから割り戻すこともできます。
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001
このように、掛け算/割り算のアプローチは、誤差を減らしますが、完全に取り除くことはできません。
ときには、分数をまったく使わないようにすることもできます。 たとえば、お店を扱っている場合、価格をドルではなくセントで保存することができます。 しかし、30% の割引を適用した場合はどうでしょうか。 実際には、端数を完全に回避することはほとんどできません。 必要に応じて「尾」を切るように丸めるだけです。
面白いことこれを実行してみてください:
// Hello! I'm a self-increasing number!alert( 9999999999999999 ); // shows 10000000000000000
これは同じ問題に悩まされます: 精度の損失です。 数字には64ビットあり、そのうち52ビットは数字を格納するのに使用できますが、それだけでは不十分です。
JavaScriptはこのようなイベントでもエラーを起こしません。
2つのゼロ数字の内部表現のもう1つのおかしな結果は、2つのゼロの存在です。
0
-0
です。これは、符号が 1 つのビットで表されるため、0 を含むすべての数に対して設定したりしなかったりすることができるからです。
ほとんどの場合、演算子がこれらを同じものとして扱うのに適しているため、この区別は気づかれません。
Tests: isFinite and isNaN
この2つの特殊な数値を覚えていますか?
-
Infinity
-Infinity
) は、何よりも大きい (小さい) 特殊な数値です。 -
NaN
は、エラーを表します。
number
という型に属していますが、「普通の」数字ではないので、それをチェックする特別な関数があります。-
isNaN(value)
NaN
であるかどうかをテストします。alert( isNaN(NaN) ); // truealert( isNaN("str") ); // true
しかし、この関数は必要なのでしょうか? 比較のために
=== NaN
NaN
は、自分自身を含め、何にも等しくないという点でユニークです。alert( NaN === NaN ); // false
isFinite(value)
true
NaN/Infinity/-Infinity
ではありません。alert( isFinite("15") ); // truealert( isFinite("str") ); // false, because a special value: NaNalert( isFinite(Infinity) ); // false, because a special value: Infinity
文字列の値が正規の数字であるかどうかを検証するために、
isFinite
が使われることがあります。let num = +prompt("Enter a number", '');// will be true unless you enter Infinity, -Infinity or not a numberalert( isFinite(num) );
空の文字列やスペースのみの文字列は、
let num = +prompt("Enter a number", '');// will be true unless you enter Infinity, -Infinity or not a numberalert( isFinite(num) );
isFinite
0
として扱われますのでご注意ください。Compare withObject.is
Object.is
===
がありますが、2つのエッジケースに対してより信頼性があります。NaN
Object.is(NaN, NaN) === true
、それは良いことです。- 値
0
-0
Object.is(0, -0) === false
は、技術的には正しいのですが、内部的には数字には符号ビットがあり、他のビットがすべてゼロであっても異なる可能性があるからです。
その他のケースでは、
Object.is(a, b)
a === b
と同じです。この比較方法は、JavaScriptの仕様でよく使われます。 内部アルゴリズムで2つの値が全く同じかどうかを比較する必要がある場合、
Object.is
(内部ではSameValueと呼ばれています)を使用します。parseInt・parseFloat
プラス
+
Number()
を使った数値変換は厳密です。alert( +"100px" ); // NaN
唯一の例外は文字列の最初や最後にあるスペースで、これらは無視されます。
しかし、実際の生活では、
"100px"
やCSSの"12pt"
のように、単位で値を設定することがよくあります。これが
parseInt
parseFloat
の役割です。これらは、文字列から数字を「読み取る」ことができるまで、文字列から数字を読み取ります。 エラーが発生した場合は、集められた数字が返されます。 関数
parseInt
parseFloat
は浮動小数点数を返します。alert( parseInt('100px') ); // 100alert( parseFloat('12.5em') ); // 12.5alert( parseInt('12.3') ); // 12, only the integer part is returnedalert( parseFloat('12.3.4') ); // 12.3, the second point stops the reading
parseInt/parseFloat
NaN
を返す場合があります。 これは、数字が読み取れなかった場合に起こります。alert( parseInt('a123') ); // NaN, the first symbol stops the process
の第2引数のparseInt(str, radix)
parseInt()
parseInt
は16進数や2進数などの文字列も解析することができます。alert( parseInt('0xff', 16) ); // 255alert( parseInt('ff', 16) ); // 255, without 0x also worksalert( parseInt('2n9c', 36) ); // 123456
その他の数学関数
JavaScriptにはMathオブジェクトが組み込まれており、数学関数や定数の小さなライブラリが含まれています。
いくつかの例を紹介します。
Math.random()
0から1(1を含まない)までの乱数を返します。
alert( Math.random() ); // 0.1234567894322alert( Math.random() ); // 0.5435252343232alert( Math.random() ); // ... (any random numbers)
Math.max(a, b, c...)
Math.min(a, b, c...)
任意の数の引数から最大/最小のものを返します。
alert( Math.max(3, 5, -10, 0, 1) ); // 5alert( Math.min(1, 2) ); // 1
Math.pow(n, power)
n
を指定された累乗に上げたものを返します。alert( Math.pow(2, 10) ); // 2 in power 10 = 1024
Math
オブジェクトには三角法をはじめ、さらに多くの関数や定数がありますが、それらはMathオブジェクトのドキュメントに記載されています。概要
ゼロが多い数字を書くには:
"e"
123e6
123
123000000
と同じです。-
"e"
123e-6
0.000123
123
百万分の一)を意味します。
異なる数字体系の場合:
- 16進法(
0x
0o
0b
)で数字を直接書くことができます。 -
parseInt(str, base)
str
base
2 ≤ base ≤ 36
を用いて、数字系の整数に解析します。 -
num.toString(base)
base
を使って、数字を数字系の文字列に変換します。
12pt
100px
のような値を数字に変換する場合:parseInt/parseFloat
を使用して、文字列から数字を読み取り、エラーが発生する前に読み取れた値を返す「ソフト」な変換を行います。
分数の場合。
Math.floor
Math.ceil
Math.trunc
Math.round
num.toFixed(precision)
を使って丸めます。- 分数を扱うときは、精度が落ちることを忘れないでください。
その他の数学関数:
- 必要なときには Math オブジェクトを参照してください。 ライブラリは非常に小さいですが、基本的なニーズをカバーすることができます
。
-
-