JavaScript/BigInt
BigInt
は、任意精度の整数を表現するためのプリミティブ型です。BigIntオブジェクトは、BigIntプリミティブ値をラップするオブジェクトです[1]。
構文
編集const bigIntLiteral = 123n; const bigIntConstructor = BigInt(123);
- リテラル表記: 数値の後に
n
を付けることで BigInt リテラルを作成できます。 - コンストラクタ:
BigInt()
関数を使用して BigInt 値を作成できます。
静的プロパティ
編集静的メソッド
編集- BigInt.asIntN(width, bigint)
- bigint を 2width で割った剰余の値の符号つき整数を返す。
- BigInt.asUintN(width, bigint)
- bigint を 2width で割った剰余の値の符号なし整数を返す。
インスタンスプロパティ
編集インスタンスメソッド
編集例
編集BigInt の基本的な使用方法
編集以下のプログラムは、BigInt の基本的な使用方法を示しています。
const bigInt1 = 1234567890123456789012345n; const bigInt2 = BigInt("9876543210987654321098765"); console.log(bigInt1); // 1234567890123456789012345n console.log(typeof bigInt1); // bigint console.log(bigInt1 + bigInt2); // 11111111101111111110111110n
このプログラムでは、BigInt リテラル構文と BigInt コンストラクタを使用して BigInt 値を作成し、それらの加算を行っています。
BigInt と Number の相互変換
編集以下のプログラムは、BigInt と Number 型の間の変換方法を示しています。
const bigInt = 123456789n; const number = Number(bigInt); console.log(number); // 123456789 const bigFromNumber = BigInt(9007199254740991); // MAX_SAFE_INTEGER console.log(bigFromNumber); // 9007199254740991n // 精度が失われる可能性がある変換 const hugeNumber = BigInt(Number.MAX_VALUE); console.log(Number(hugeNumber)); // 1.7976931348623157e+308
このプログラムでは、BigInt から Number への変換、および Number から BigInt への変換を示しています。ただし、大きな値では精度が失われる可能性があることに注意してください。
BigInt の算術演算
編集以下のプログラムは、BigInt での算術演算の例を示しています。
const a = 1234567890123456789n; const b = 9876543210987654321n; console.log(a + b); // 11111111101111111110n console.log(a - b); // -8641975320864197532n console.log(a * b); // 12193263111263526900609672107023853369n console.log(a / b); // 0n (小数部は切り捨て) console.log(a % b); // 1234567890123456789n console.log(a ** 3n); // 1881676377434183981909562699940347954574863968n
このプログラムでは、BigInt での加算、減算、乗算、除算、剰余、冪乗などの基本的な算術演算を示しています。
注意点
編集- 型の混合: BigInt と Number を直接混合して演算することはできません。明示的な変換が必要です。
- 丸め: BigInt の除算では、結果は常に整数に切り捨てられます。
- プロトタイプメソッド: BigInt.prototype には、valueOf()、toString()、toLocaleString() などのメソッドがあります。
- JSON化: BigInt 値は、標準の JSON.stringify() ではシリアライズされません。カスタムシリアライズが必要です。
- ビット演算子: BigInt は多くのビット演算子(&, |, ^, <<, >>, ~)をサポートしていますが、>>>(符号なし右シフト)は使用できません。
附録
編集Object.defineProperties()
を使用してBigInt.prototype
にabs
、sign
、pow
、sqrt
などのpolyfillを実装する例を示します。
if (typeof BigInt !== 'undefined') { Object.defineProperties(BigInt.prototype, { abs: { value: function () { return this < 0n ? -this : this; }, writable: true, enumerable: false, configurable: true, }, sign: { value: function () { return this === 0n ? 0n : this < 0n ? -1n : 1n; }, writable: true, enumerable: false, configurable: true, }, pow: { value: function (exponent) { if (exponent < 0n) { throw new RangeError('Exponent must be non-negative'); } if (exponent === 0n) { return 1n; } if (exponent === 1n) { return this; } let result = 1n; let base = this; while (exponent > 0n) { if (exponent % 2n === 1n) { result *= base; } base *= base; exponent /= 2n; } return result; }, writable: true, enumerable: false, configurable: true, }, sqrt: { value: function () { if (this < 0n) { throw new RangeError('Cannot calculate square root of a negative BigInt'); } if (this < 2n) { return this; } const newtonStep = (n, x) => (x + n / x) >> 1n; const initialGuess = (this >> (BigInt(this.toString(16).length) - 1n)) + 1n; let x0 = initialGuess; let x1 = newtonStep(this, x0); while (x1 < x0) { x0 = x1; x1 = newtonStep(this, x0); } return x0; }, writable: true, enumerable: false, configurable: true, }, gcd: { value: function (other) { if (typeof other !== 'bigint') { throw new TypeError('Argument must be a BigInt'); } let a = this.abs(); let b = other.abs(); if (b === 0n) { return a; } let r; while ((r = a % b) !== 0n) { a = b; b = r; } return b; }, writable: true, enumerable: false, configurable: true, }, lcm: { value: function (other) { if (typeof other !== 'bigint') { throw new TypeError('Argument must be a BigInt'); } if (this === 0n || other === 0n) { return 0n; } return (this / this.gcd(other)) * other; }, writable: true, enumerable: false, configurable: true, }, }); } // 使用例 if (typeof BigInt !== 'undefined') { const bigIntValue = -123n; console.log(bigIntValue.abs()); // 123n console.log(bigIntValue.sign()); // -1n console.log(2n.pow(10n)); // 1024n console.log(25n.sqrt()); // 5n console.log(26n.sqrt()); // 5n console.log(12n.gcd(18n)); // 6n console.log(12n.lcm(18n)); // 36n }
- 解説
- ;
Object.defineProperties()
の使用Object.defineProperties(BigInt.prototype, { ... })
を使用して、BigInt.prototype
に複数のプロパティ(メソッド)を一度に追加しています。
- ; 各メソッドの実装
abs()
: 絶対値を返すメソッド。sign()
: 符号を返すメソッド(-1n、0n、1n)。pow()
: べき乗を計算するメソッド。sqrt()
: 平方根を計算するメソッド(ニュートン法を使用)。gcd(other)
: 2つのBigInt
の最大公約数(GCD)を返すメソッド。lcm(other)
: 2つのBigInt
の最小公倍数(LCM)を返すメソッド。
- プロパティの属性
writable: true
: メソッドを上書き可能にします。enumerable: false
:for...in
ループで列挙されないようにします。configurable: true
: メソッドの削除や属性の変更を可能にします。
- 使用例
- 実装したメソッドの使用例を示しています。
- 注意点
sqrt()
メソッドは、ニュートン法を使用しているため、近似値を返します。pow()
メソッドは、負の指数をサポートしていません。gcd(other)
メソッドは、ユークリッドの互除法を使用して実装している。- 引数
other
がBigInt
型でない場合は、TypeError
をスロー。
- 引数
lcm(other)
メソッドは、 GCDを使用してLCMを計算。- 引数
other
がBigInt
型でない場合は、TypeError
をスロー。 - どちらかの値が0nの場合0nを返す。
- 引数
- これらのpolyfillは、すべてのエッジケースを網羅しているわけではありません。必要に応じて、テストを追加し、実装を改善してください。
BigInt
が実装されていない環境では、これらのpolyfillは動作しません。
脚註
編集- ^ BigIntは、Number型で表現できる範囲を超える整数値を扱うために導入されました。