数値展開

2進数と8進数の表記

ES6 は、それぞれ接頭辞 '0b' (または '0B') および '0o' (または '0O') で表される、2 進値および 8 進値を記述する新しい方法を提供します。

0b111110111 === 503 // true
0o767 === 503 // true

ES5 以降、厳密モードでは、接頭辞 '0' で 8 進数を表すことができなくなり、ES6 では接頭辞 '0o' を使用する必要があることがさらに明確になりました。

// 非厳密モード
(関数(){
  console.log(0o11 === 011);
})() // 真実

// 厳密モード
(関数(){
  '厳密を使用';
  console.log(0o11 === 011);
})() // キャッチされない SyntaxError: 8 進リテラルは厳密モードでは許可されません。

0b0o の接頭辞が付いた文字列値を 10 進数に変換したい場合は、Number メソッドを使用します。

Number('0b111') // 7
Number('0o10') // 8

値の区切り文字

ヨーロッパおよびアメリカの言語では、値が長い場合、3 桁ごとに区切り文字 (通常はカンマ) を追加して、値を読みやすくすることができます。たとえば、「1000」は「1,000」と書くことができます。

ES2021 では、JavaScript 値で区切り文字としてアンダースコア (_) を使用できるようになります。

予算 = 1_000_000_000_000 とします。
予算 === 10 ** 12 // true

この値区切り文字は、間隔の桁数を指定しません。つまり、3 桁ごとに区切り文字を追加することも、各桁、2 桁ごと、または 4 桁ごとに区切り文字を追加することもできます。

123_00 === 12_300 // true

12345_00 === 123_4500 // true
12345_00 === 1_234_500 // true

10 進数および科学的表記法でも値の区切り文字を使用できます。

// 10進数
0.000_001

// 科学的表記法
1e10_000

数値区切り文字を使用する場合は、いくつかの注意点があります。

・値の前(先頭)や最後(後)には配置できません。 ・セパレータを2枚以上連結することはできません。 ・小数点の前後に区切り文字を入れることはできません。

  • 科学的記数法では、指数を表す 'e' または 'E' の前後に区切り文字を置くことはできません。

次の書き込みメソッドではエラーが報告されます。

// すべてのエラーを報告する
3_.141
3._141
1_e12
1e_12
123__456
_1464301
1464301_

10 進数に加えて、他の基数の値にも区切り文字を使用できます。

//バイナリ
0b1010_0001_1000_0101
// 16進数
0xA0_B0_C0

ご覧のとおり、値デリミタは値をバイト順に区切ることができるため、バイナリビットを操作する場合に非常に便利です。

区切り文字は、ベース プレフィックス 0b0B0o0O0x0X の直後に置くことはできないことに注意してください。

// エラーを報告する
0_b111111000
0b_111111000

値の区切り文字は単に記述の便宜を図るためのものであり、JavaScript の内部値の保存と出力には影響しません。

数値 = 12_345 とします。

数値 // 12345
num.toString() // 12345

上記の例では、変数 num の値は 12_345 ですが、内部的に格納および出力する際に​​数値区切り文字はありません。

文字列を数値に変換する以下の 3 つの関数は、数値区切り文字をサポートしていません。主な理由は、言語の設計者が、値区切り記号は外部入力データを処理するためではなく、主にコーディング中に値を書き込むためのものであると考えているためです。

-番号() -parseInt() -parseFloat()

Number('123_456') // NaN
parseInt('123_456') // 123

Number.isFinite()、Number.isNaN()

ES6 は、Number オブジェクトに対して 2 つの新しいメソッド、Number.isFinite()Number.isNaN() を提供します。

Number.isFinite() は、値が有限かどうか、つまり Infinity ではないかどうかをチェックするために使用されます。

Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false

パラメータの型が数値でない場合、Number.isFinite は常に false を返すことに注意してください。

Number.isNaN() は、値が NaN であるかどうかをチェックするために使用されます。

Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // true

パラメータの型が NaN でない場合、Number.isNaN は常に false を返します。

従来のグローバルメソッドである isFinite() や isNaN() との違いは、従来のメソッドではまず Number() を呼び出して数値以外の値を数値に変換してから判断するのに対し、これら 2 つの新しいメソッドは数値に対してのみ有効です。「Number.isFinite()」は数値以外の値に対して常に「false」を返します。「Number.isNaN()」は「NaN」および非「NaN」に対してのみ「true」を返します。 は常にfalse` を返します。

isFinite(25) // true
isFinite("25") // true
Number.isFinite(25) // true
Number.isFinite("25") // false

isNaN(NaN) // true
isNaN("NaN") // true
Number.isNaN(NaN) // true
Number.isNaN("NaN") // false
Number.isNaN(1) // false

Number.parseInt()、Number.parseFloat()

ES6 では、グローバル メソッド parseInt()parseFloat()Number オブジェクトに移植されており、動作はまったく変わりません。

// ES5の書き込み方法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45

// ES6の書き込み方法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45

この目的は、グローバル メソッドを徐々に減らし、言語を徐々にモジュール化することです。

Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true

Number.isInteger()

Number.isInteger() は、値が整数であるかどうかを判断するために使用されます。

Number.isInteger(25) // true
Number.isInteger(25.1) // false

JavaScript の内部では、整数と浮動小数点数は同じ方法で格納されるため、25 と 25.0 は同じ値として扱われます。

Number.isInteger(25) // true
Number.isInteger(25.0) // true

引数が数値でない場合、Number.isIntegerfalse を返します。

Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false

JavaScript は IEEE 754 標準を採用しているため、値は 64 ビットの倍精度形式で格納され、数値精度は最大 53 バイナリ ビット (1 隠しビットと 52 有効ビット) に達する可能性があることに注意してください。値の精度がこの制限を超えると、54 ビット目以降が破棄されます。この場合、Number.isInteger は誤判定する可能性があります。

Number.isInteger(3.0000000000000002) // true

上記のコードでは、Number.isInteger のパラメータは明らかに整数ではありませんが、true を返します。その理由は、この 10 進数の精度が小数点以下 16 桁に達し、2 進数への変換が 53 桁を超えるため、最後の '2' が切り捨てられるためです。

同様の状況で、値の絶対値が Number.MIN_VALUE (5E-324) より小さい場合、つまり JavaScript が区別できる最小値より小さい場合、その値は自動的に 0 に変換されます。このとき、 Number.isInteger も判定を誤ります。

Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true

上記のコードでは、「5E-325」は値が小さすぎるため自動的に0に変換され、「true」を返します。

つまり、データの精度に対する要件が高い場合、値が整数であるかどうかを判断するために Number.isInteger() を使用することはお勧めできません。

Number.EPSILON

ES6 は、非常に小さな定数 Number.EPSILONNumber オブジェクトに追加します。仕様によれば、これは 1 と 1 より大きい最小の浮動小数点数との差を表します。

64 ビット浮動小数点数の場合、1 より大きい最小の浮動小数点数は、小数点の後に 51 個の連続するゼロを含む 2 進数の「1.00..001」に相当します。この値から 1 を引いた値は、2 の -52 乗に相当します。

Number.EPSILON === Math.pow(2, -52)
// 真実
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// "0.00000000000000022204"

Number.EPSILON は、実際には JavaScript が表現できる最小精度です。誤差がこの値より小さい場合は、意味がない、つまり誤差がないとみなしてよい。

このような少量を導入する目的は、浮動小数点計算の誤差範囲を設定することです。浮動小数点計算が不正確であることはわかっています。

0.1+0.2
// 0.30000000000000004

0.1 + 0.2 - 0.3
// 5.551115123125783e-17

5.551115123125783e-17.toFixed(20)
// '0.00000000000000005551'

上記のコードは、「0.1 + 0.2」と「0.3」を比較すると「false」という結果が得られる理由を説明しています。

0.1 + 0.2 === 0.3 // false

Number.EPSILON を使用して「許容誤差範囲」を設定できます。たとえば、誤差範囲は 2 の -50 乗 (つまり、「Number.EPSILON * Math.pow(2, 2)」) に設定されます。つまり、2 つの浮動小数点数の差がこの値より小さい場合、 2 つの浮動小数点数は等しいとみなします。

5.551115123125783e-17 < Number.EPSILON * Math.pow(2, 2)
// 真実

したがって、「Number.EPSILON」の本質は、許容可能な最小誤差範囲です。

関数 insideErrorMargin (左、右) {
  return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}

0.1 + 0.2 === 0.3 // false
insideErrorMargin(0.1 + 0.2, 0.3) // true

1.1 + 1.3 === 2.4 // false
insideErrorMargin(1.1 + 1.3, 2.4) // true

上記のコードは浮動小数点数演算であり、エラー チェック機能を展開しています。

安全な整数と Number.isSafeInteger()

JavaScript が正確に表現できる整数の範囲は -2^53 から 2^53 までです (この範囲を超えると、値は正確に表現できません)。

Math.pow(2, 53) // 9007199254740992

9007199254740992 // 9007199254740992
9007199254740993 // 9007199254740992

Math.pow(2, 53) === Math.pow(2, 53) + 1
// 真実

上記のコードでは、2 の 53 乗を超えると数値が不正確になります。

ES6 では、この範囲の上限と下限を表す 2 つの定数 Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER が導入されました。

Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
// 真実
Number.MAX_SAFE_INTEGER === 9007199254740991
// 真実

Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER
// 真実
Number.MIN_SAFE_INTEGER === -9007199254740991
// 真実

上記のコードでは、JavaScript が正確に表現できるものの限界がわかります。

Number.isSafeInteger() は、整数がこの範囲内にあるかどうかを判断するために使用されます。

Number.isSafeInteger('a') // false
Number.isSafeInteger(null) // false
Number.isSafeInteger(NaN) // false
Number.isSafeInteger(Infinity) // false
Number.isSafeInteger(-Infinity) // false

Number.isSafeInteger(3) // true
Number.isSafeInteger(1.2) // false
Number.isSafeInteger(9007199254740990) // true
Number.isSafeInteger(9007199254740992) // false

Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false

この関数の実装は非常に簡単で、安全な整数の 2 つの境界値と比較するだけです。

Number.isSafeInteger = 関数 (n) {
  return (typeof n === '数値' &&
    Math.round(n) === n &&
    Number.MIN_SAFE_INTEGER <= n &&
    n <= Number.MAX_SAFE_INTEGER);
}

実際にこの機能を使用する場合は注意が必要です。演算の結果が安全な整数の範囲内にあることを検証します。演算の結果を検証するだけでなく、演算に含まれるすべての値も検証します。

Number.isSafeInteger(9007199254740993)
// 間違い
Number.isSafeInteger(990)
// 真実
Number.isSafeInteger(9007199254740993 - 990)
// 真実
9007199254740993-990
// 結果 9007199254740002 を返します
// 正解は 9007199254740003 です

上記のコードでは、9007199254740993 は安全な整数ではありませんが、Number.isSafeInteger は計算結果が安全であることを示す結果を返します。これは、この数値が精度の範囲を超えており、「9007199254740992」の形式でコンピューターに保存されるためです。

9007199254740993 === 9007199254740992
// 真実

したがって、演算結果が安全な整数であるかどうかだけを検証すると、誤った結果が得られる可能性があります。次の関数は、2 つのオペランドと演算結果を同時に検証できます。

関数 trusty (左、右、結果) {
  もし (
    Number.isSafeInteger(左) &&
    Number.isSafeInteger(右) &&
    Number.isSafeInteger(結果)
  ) {
    結果を返します。
  }
  throw new RangeError('操作は信頼できません!');
}

信頼できる(9007199254740993, 990, 9007199254740993 - 990)
// RangeError: 操作は信頼できません!

信頼できる(1, 2, 3)
// 3

Math オブジェクトの拡張

ES6 では、Math オブジェクトに 17 個の新しい数学関連メソッドが追加されています。これらのメソッドはすべて静的メソッドであり、Math オブジェクトに対してのみ呼び出すことができます。

Math.trunc()

Math.trunc メソッドは、数値の小数部分を削除し、整数部分を返すために使用されます。

Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0

数値以外の値の場合、Math.trunc は内部で Number メソッドを使用して、最初に数値に変換します。

Math.trunc('123.456') // 123
Math.trunc(true) //1
Math.trunc(false) // 0
Math.trunc(null) // 0

null 値および整数に切り捨てられない値の場合は、NaN が返されます。

Math.trunc(NaN); // NaN
Math.trunc('foo'); // NaN
Math.trunc(); // NaN
Math.trunc(未定義) // NaN

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.trunc = Math.trunc || 関数(x) {
  戻り値 x < 0 ? Math.ceil(x) : Math.floor(x);
};

Math.sign()

Math.sign メソッドは、数値が正、負、ゼロのいずれであるかを判断するために使用されます。数値以外の場合は、まず数値に変換されます。

5 つの値を返します。

  • パラメータが正の数の場合は、「+1」を返します。
  • パラメータが負の数の場合は、「-1」を返します。
  • パラメータが 0 の場合、「0」を返します。
  • パラメータが -0 の場合、「-0」を返します。
  • それ以外の値の場合は NaN が返されます。
Math.sign(-5) // -1
Math.sign(5) // +1
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign(NaN) // NaN

パラメータが数値以外の場合は、自動的に数値に変換されます。数値に変換できない値の場合は「NaN」を返します。

Math.sign('') // 0
Math.sign(true) // +1
Math.sign(false) // 0
Math.sign(null) // 0
Math.sign('9') // +1
Math.sign('foo') // NaN
Math.sign() // NaN
Math.sign(未定義) // NaN

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.sign = Math.sign 関数(x) {
  x = +x // 数値に変換します。
  if (x === 0 || isNaN(x)) {
    x を返します。
  }
  x > 0 : -1 を返します。
};

Math.cbrt()

Math.cbrt() メソッドは、数値の立方根を計算するために使用されます。

Math.cbrt(-1) // -1
Math.cbrt(0) // 0
Math.cbrt(1) // 1
Math.cbrt(2) // 1.2599210498948732

数値以外の値の場合、最初に Math.cbrt() メソッド内で Number() メソッドが使用され、数値に変換されます。

Math.cbrt('8') // 2
Math.cbrt('hello') // NaN

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.cbrt = Math.cbrt || 関数(x) {
  var y = Math.pow(Math.abs(x), 1/3);
  x < 0 ? -y : y を返します。
};

Math.clz32()

Math.clz32() メソッドは、引数を 32 ビット符号なし整数に変換し、32 ビット値の先頭の 0 の数を返します。

Math.clz32(0) // 32
Math.clz32(1) // 31
Math.clz32(1000) // 22
Math.clz32(0b0100000000000000000000000000000) // 1
Math.clz32(0b0010000000000000000000000000000) // 2

上記のコードでは、0 のバイナリ形式はすべて 0 であるため、先頭に 0 が 32 個あります。1 のバイナリ形式は '0b1' であり、これは 1 ビットのみを占めるため、32 ビット中に先頭の 0 が 31 個あります。 1000 の形式は 0b1111101000 で、合計 10 ビットがあるため、32 ビット中に先頭の 0 が 22 個あります。

関数名「clz32」は、「数値の 32 ビット 2 進数表現の先頭のゼロ ビットをカウントする」の略語に由来しています。

左シフト演算子 (<<) は、Math.clz32 メソッドに直接関連しています。

Math.clz32(0) // 32
Math.clz32(1) // 31
Math.clz32(1 << 1) // 30
Math.clz32(1 << 2) // 29
Math.clz32(1 << 29) // 2

小数の場合、「Math.clz32」メソッドは整数部分のみを考慮します。

Math.clz32(3.2) // 30
Math.clz32(3.9) // 30

Null 値またはその他のタイプの値の場合、「Math.clz32」メソッドはまずそれらを数値に変換してから計算します。

Math.clz32() // 32
Math.clz32(NaN) // 32
Math.clz32(無限大) // 32
Math.clz32(null) // 32
Math.clz32('foo') // 32
Math.clz32([]) // 32
Math.clz32({}) // 32
Math.clz32(true) // 31

Math.imul()

Math.imul メソッドは、2 つの数値を乗算した結果を 32 ビット符号付き整数の形式で返します。これも 32 ビット符号付き整数です。

Math.imul(2, 4) // 8
Math.imul(-1, 8) // -8
Math.imul(-2, -2) // 4

最後の 32 ビットだけを考慮すると、ほとんどの場合、Math.imul(a, b)a * b の結果は同じになります。つまり、このメソッドは (a * b)|0 (32ビットを超える部分はオーバーフローします)。このメソッドを導入する必要がある理由は、JavaScript には精度の制限があり、2 の 53 乗を超える値を正確に表現できないためです。これは、非常に大きな数値の乗算では、下位桁の値が不正確になることがよくありますが、「Math.imul」メソッドは正しい下位桁の値を返すことができることを意味します。

(0x7fffffff * 0x7fffffff)|0 // 0

上記の乗算計算の結果は 0 を返します。しかし、両方の 2 進数の最下位ビットが 1 であるため、この結果は正しくないはずです。2 進数の乗算によれば、計算結果の 2 進数の最下位ビットも 1 になるはずです。このエラーは、積が 2 の 53 乗を超えており、JavaScript が余分な精度を保存できないため、下位の値が 0 に変更されることが原因です。 Math.imul メソッドは正しい値 1 を返すことができます。

Math.imul(0x7ffffffff, 0x7fffffff) // 1

Math.from()

Math.fromround メソッドは、32 ビット単精度浮動小数点形式の数値を返します。

32 ビットの単精度形式の場合、数値精度は 24 バイナリ ビット (1 つの隠れビットと 23 の有効ビット) であるため、-224 から 224 の場合、 (2 つのエンドポイントを除く) 間の整数の場合、戻り結果はパラメーター自体と一致します。

Math.from(0) // 0
Math.from(1) // 1
Math.fromround(2 ** 24 - 1) // 16777215

パラメータの絶対値が 224 より大きい場合、返される結果の精度が低下し始めます。

Math.fromround(2 ** 24) // 16777216
Math.fromround(2 ** 24 + 1) // 16777216

Math.fromround メソッドの主な機能は、64 ビットの倍精度浮動小数点数を 32 ビットの単精度浮動小数点数に変換することです。 10 進数の精度が 24 進数の 24 桁を超える場合、戻り値は元の値とは異なります。それ以外の場合、戻り値は変更されません (つまり、64 ビット倍精度値と一致します)。

// 有効な精度は失われません
Math.from(1.125) // 1.125
Math.from(7.25) // 7.25

// 精度が失われる
Math.fromround(0.3) // 0.30000001192092896
Math.fromround(0.7) // 0.699999988079071
Math.around(1.0000000123) // 1

NaN および Infinity の場合、このメソッドは元の値を返します。他のタイプの非数値の場合、「Math.fromround」メソッドは最初にそれらを数値に変換し、次に単精度浮動小数点数に返します。

Math.around(NaN) // NaN
Math.fromround(Infinity) // 無限大

Math.from('5') // 5
Math.from(true) // 1
Math.from(null) // 0
Math.from([]) // 0
Math.fromround({}) // NaN

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.fround = Math.fround 関数 (x) {
  新しい Float32Array([x])[0] を返します。
};

Math.hypot()

Math.hypot メソッドは、すべての引数の二乗和の平方根を返します。

Math.hypot(3, 4); // 5
Math.hypot(3, 4, 5); // 7.0710678118654755
Math.hypot(); // 0
Math.hypot(NaN); // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot(3, 4, '5') // 7.0710678118654755
Math.hypot(-3); // 3

上記のコードでは、3 の 2 乗と 4 の 2 乗は 5 の 2 乗と等しくなります。

引数が数値でない場合、Math.hypot メソッドはそれを数値に変換します。パラメータを数値に変換できない場合は、NaN が返されます。

対数法

ES6 では、4 つの新しい対数相関メソッドが追加されています。

(1) Math.expm1()

Math.expm1(x) は ex - 1、つまり Math.exp(x) - 1 を返します。

Math.expm1(-1) // -0.6321205588285577
Math.expm1(0) // 0
Math.expm1(1) // 1.718281828459045

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.expm1 = Math.expm1 || 関数(x) {
  Math.exp(x) - 1 を返します。
};

(2)Math.log1p()

Math.log1p(x) メソッドは、1 + x の自然対数、つまり Math.log(1 + x) を返します。 x が -1 より小さい場合、NaN を返します。

Math.log1p(1) // 0.6931471805599453
Math.log1p(0) // 0
Math.log1p(-1) // -無限大
Math.log1p(-2) // NaN

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.log1p = Math.log1p || 関数(x) {
  Math.log(1 + x) を返します。
};

(3)Math.log10()

Math.log10(x) は、x の底 10 の対数を返します。 x が 0 未満の場合は、NaN を返します。

Math.log10(2) // 0.3010299956639812
Math.log10(1) // 0
Math.log10(0) // -無限大
Math.log10(-2) // NaN
Math.log10(100000) // 5

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.log10 = Math.log10 || 関数(x) {
  Math.log(x) / Math.LN10 を返します。
};

(4)Math.log2()

Math.log2(x) は、x の底 2 の対数を返します。 x が 0 未満の場合は、NaN を返します。

Math.log2(3) // 1.584962500721156
Math.log2(2) // 1
Math.log2(1) // 0
Math.log2(0) // -無限大
Math.log2(-2) // NaN
Math.log2(1024) // 10
Math.log2(1 << 29) // 29

このメソッドがデプロイされていない環境では、次のコードを使用してシミュレートできます。

Math.log2 = Math.log2 || 関数(x) {
  Math.log(x) / Math.LN2 を返します。
};

双曲線関数法

ES6 では、6 つの新しい双曲線関数メソッドが追加されています。

  • Math.sinh(x) は、x の双曲線サインを返します。
  • Math.cosh(x) は、x の双曲線余弦を返します。
  • Math.tanh(x) は、x の双曲線正接を返します。
  • Math.asinh(x) は、x の逆双曲線正弦を返します。
  • Math.acosh(x) は、x の逆双曲線余弦を返します。
  • Math.atanh(x) は、x の逆双曲線正接を返します。

BigInt データ型

導入

JavaScript のすべての数値は 64 ビット浮動小数点数として格納されるため、値の表現に 2 つの大きな制限が生じます。まず、数値の精度は 2 進数で 53 桁 (10 進数の 16 桁に相当) までしかないため、JavaScript はこの範囲を超える整数を正確に表すことができず、科学や金融における正確な計算には適していません。 2 番目は、2 の 1024 乗以上の値です。JavaScript ではこれを表現できないため、「Infinity」が返されます。

// 2進数53桁を超える値は精度を維持できません
Math.pow(2, 53) === Math.pow(2, 53) + 1 // true

// 2の1024乗を超える値は表現できません
Math.pow(2, 1024) // 無限大

ES2020 では、この問題を解決するために新しいデータ型 BigInt (big integer) が導入されています。これは ECMAScript の 8 番目のデータ型です。 BigInt は整数を表すためにのみ使用され、桁数に制限はありません。任意の桁数の整数を正確に表現できます。

定数 a = 2172141653n;
const b = 15346349309n;

// BigInt は精度を維持できる
a * b // 33334444555566667777n

// 通常の整数は精度を維持できません
数値(a) * 数値(b) // 33334444555566670000

Number 型と区別するために、BigInt 型のデータには接尾辞 'n' を付ける必要があります。

1234 // 通常の整数
1234n // BigInt

// BigInt 操作
1n + 2n // 3n

BigInt は、すべて接尾辞 'n' を付けて、さまざまな基数で表現することもできます。

0b1101n // バイナリ
0o777n // 8進数
0xFFn // 16進数

BigInt と通常の整数は 2 種類の値であり、互いに等しくありません。

42n === 42 // false

「typeof」演算子は、BigInt 型のデータに対して「bigint」を返します。

typeof 123n // 'bigint'

BigInt では負符号 (-) を使用できますが、正符号 (+) は asm.js と競合するため使用できません。

-42n // 正しい
+42n // エラーレポート

JavaScript はこれまで、表現できる精度を超えていたため、70 の階乗 (つまり、「70!」) を計算できませんでした。

p = 1 とします。
for (let i = 1; i <= 70; i++) {
  p *= i;
}
コンソール.log(p); // 1.197857166996989e+100

大きな整数がサポートされるようになったので、ブラウザの開発者ツールで次のコードを実行すれば問題ありません。

p = 1n とします。
for (let i = 1n; i <= 70n; i++) {
  p *= i;
}
コンソール.log(p); // 11978571...00000000n

BigInt 関数

JavaScript はネイティブで「BigInt」関数を提供しており、これを使用して BigInt 型の値を生成できます。変換ルールは基本的に、他の型の値を BigInt に変換する Number() と同じです。

BigInt(123) // 123n
BigInt('123') // 123n
BigInt(false) // 0n
BigInt(true) // 1n

BigInt() 関数にはパラメータが必要であり、パラメータは正常に数値に変換できる必要があります。次の使用法ではエラーが報告されます。

new BigInt() // TypeError
BigInt(未定義) //TypeError
BigInt(null) // TypeError
BigInt('123n') // 構文エラー
BigInt('abc') // 構文エラー

上記のコードでは、文字列 123n を Number 型に解析できないため、エラーが報告されることに特に注目してください。

パラメータが 10 進数の場合もエラーが報告されます。

BigInt(1.5) // RangeError
BigInt('1.5') // 構文エラー

BigInt は、Object オブジェクトの 2 つのインスタンス メソッドを継承します。

  • BigInt.prototype.toString()
  • BigInt.prototype.valueOf()

また、Number オブジェクトからインスタンス メソッドも継承します。

  • BigInt.prototype.toLocaleString()

さらに、3 つの静的メソッドが提供されます。

  • BigInt.asUintN(width, BigInt): 指定された BigInt を 0 から 2width - 1 までの対応する値に変換します。
  • BigInt.asIntN(width, BigInt): 指定された BigInt を、-2width - 1 と 2width - 1 - 1 の間の対応する値に変換します。
  • BigInt.parseInt(string[, radix]): Number.parseInt() と同様に、指定された基数で文字列を BigInt に変換します。
const max = 2n ** (64n - 1n) - 1n;

BigInt.asIntN(64、最大)
// 9223372036854775807n
BigInt.asIntN(64、最大 + 1n)
// -9223372036854775808n
BigInt.asUintN(64、最大 + 1n)
// 9223372036854775808n

上記のコードでは、「max」は 64 ビットの符号付き BigInt で表現できる最大値です。この値に 1n を加算すると、追加ビットが符号ビットとして解釈されるため、BigInt.asIntN() は負の値を返します。 BigInt.asUintN() メソッドは符号ビットがないため、結果を正しく返すことができます。

BigInt.asIntN() および BigInt.asUintN() で指定された桁数が値自体の桁数より小さい場合、先頭ビットは破棄されます。

const max = 2n ** (64n - 1n) - 1n;

BigInt.asIntN(32, max) // -1n
BigInt.asUintN(32, 最大) // 4294967295n

上記のコードでは、「max」は 64 ビットの BigInt であり、32 ビットに変換されると、最初の 32 ビットが破棄されます。

以下は「BigInt.parseInt()」の例です。

// Number.parseInt() と BigInt.parseInt() の比較
Number.parseInt('9007199254740993', 10)
// 9007199254740992
BigInt.parseInt('9007199254740993', 10)
// 9007199254740993n

上記のコードでは、有効な数値の数が最大制限を超えているため、Number.parseInt メソッドによって返される結果は不正確ですが、BigInt.parseInt メソッドは対応する BigInt を正しく返します。

バイナリ配列の場合、BigInt は 2 つの新しい型、BigUint64ArrayBigInt64Array を追加します。どちらのデータ型も 64 ビット BigInt を返します。 「DataView」オブジェクトのインスタンス メソッド「DataView.prototype.getBigInt64()」および「DataView.prototype.getBigUint64()」も BigInt を返します。

変換ルール

Boolean()Number()、および String() の 3 つのメソッドを使用して、BigInt をブール型、数値型、および文字列型に変換できます。

Boolean(0n) // false
Boolean(1n) // true
数値(1n) // 1
String(1n) // "1"

上記のコードでは、最後の例に注目してください。接尾辞「n」は文字列に変換されると消えます。

さらに、否定演算子 (!) も BigInt をブール値に変換できます。

!0n // true
!1n // false

数学演算

数学的演算に関しては、BigInt 型の 4 つの二項演算子 +-*、および ** は Number 型と同じ動作をします。除算演算「/」は小数部分を四捨五入して整数を返します。

9n/5n
// 1n

BigInt では、2 つの例外を除いて、ほぼすべての数値演算子を使用できます。

  • 符号なし右シフト演算子 >>>>
  • 単項正演算子 +

上記の 2 つの演算子は、BigInt で使用するとエラーを報告します。前者は、>>>> 演算子は符号なしですが、BigInt は常に符号付きであるため、この演算は無意味であり、右シフト演算子 >> と完全に同等になります。後者は、asm.js では単項演算子 + が常に Number 型を返すため、asm.js を損傷しないように、+1n はエラーを報告することが規定されています。

BigInt を通常の数値と混合することはできません。

1n + 1.3 // エラーレポート

BigInt または Number のどちらが返されるかに関係なく、精度情報が失われるため、上記のコードはエラーを報告します。たとえば、式 (2n**53n + 1n) + 0.5 が BigInt 型を返す場合、0.5 の小数部分は失われます。Number 型が返される場合、有効な精度は 53 桁しか維持できません。精度の低下につながります。

同じ理由で、標準ライブラリ関数が Number 型のパラメーターを予期していても BigInt を取得した場合、エラーが報告されます。

//書き方が間違っています
Math.sqrt(4n) // エラー

// 正しい書き方
Math.sqrt(Number(4n)) // 2

上記のコードでは、Math.sqrt のパラメーターは Number 型であることが想定されており、それが BigInt である場合、計算を実行する前に Number メソッドを使用して型を変換する必要があります。

asm.js では、「|0」の後に値を指定すると、32 ビット整数が返されます。 Number 型と演算を混在させることはできないというルールに従って、BigInt は |0 で演算するとエラーを報告します。

1n | 0 // エラーレポート

その他の操作

BigInt に対応するブール値は Number 型と一致します。つまり、「0n」は「false」に変換され、その他の値は「true」に変換されます。

if (0n) {
  console.log('if');
} それ以外 {
  console.log('else');
}
//それ以外

上記のコードでは、「0n」が「false」に相当するため、「else」句に入ります。

比較演算子 (「>」 など) と等価演算子 (「==」) を使用すると、精度を失うことなく BigInt 計算を他のタイプの値と混合できます。

0n < 1 // true
0n < true // true
0n == 0 // true
0n == false // true
0n === 0 // false

BigInt と文字列が混在する場合は、まず文字列に変換されてから演算が実行されます。

'' + 123n // "123"

作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0