1. Number
型の場合
JavaScript の通常の数値は Number
型で、絶対値の長さが 53 ビットの整数を扱うことができます。
参考「Number.MIN_SAFE_INTEGER - JavaScript | MDN」
参考「Number.MAX_SAFE_INTEGER - JavaScript | MDN」
ただし、JavaScript でのビット演算は数値を 32 ビットとして扱います。
参考「バイナリービット演算子 - 式と演算子 - JavaScript | MDN」
そのため、ビット演算の右シフトでなく割り算を用いて長さを 32 ビット以下の値に分割する必要があります。
/**
* 整数をビッグエンディアン形式で Uint8Array に変換する
*/
const intToUint8ArrayInBigEndian = number => {
// メモ: number が負の場合、Math.floor() なしだと正しい結果を得られないため注意
const highOrderDigits = Math.floor(number / 0x1_00000000);
//
const uint8Array = new Uint8Array(8);
uint8Array[0] = highOrderDigits >>> 24 & 0xff;
uint8Array[1] = highOrderDigits >>> 16 & 0xff;
uint8Array[2] = highOrderDigits >>> 8 & 0xff;
uint8Array[3] = highOrderDigits & 0xff;
uint8Array[4] = number >>> 24 & 0xff;
uint8Array[5] = number >>> 16 & 0xff;
uint8Array[6] = number >>> 8 & 0xff;
uint8Array[7] = number & 0xff;
return uint8Array;
};
例
// 絶対値の長さが 53 ビットの正の整数
const numberA = 0x123456_789abcde;
console.log(numberA.toString(16));
const uint8ArrayA = intToUint8ArrayInBigEndian(numberA);
console.log(Array.from(uint8ArrayA, uint8 => uint8.toString(16).padStart(2, '0')).join());
// 絶対値の長さが 53 ビットの正の整数
const numberB = Number.MAX_SAFE_INTEGER;
console.log(numberB.toString(16));
const uint8ArrayB = intToUint8ArrayInBigEndian(numberB);
console.log(Array.from(uint8ArrayB, uint8 => uint8.toString(16).padStart(2, '0')).join());
// 絶対値の長さが 53 ビットの負の整数
const numberC = Number.MIN_SAFE_INTEGER;
console.log(numberC.toString(16));
const uint8ArrayC = intToUint8ArrayInBigEndian(numberC);
console.log(Array.from(uint8ArrayC, uint8 => uint8.toString(16).padStart(2, '0')).join());
例の実行結果
123456789abcde
00,12,34,56,78,9a,bc,de
1fffffffffffff
00,1f,ff,ff,ff,ff,ff,ff
-1fffffffffffff
ff,e0,00,00,00,00,00,01
ビット演算の右シフトは以下のように割り算で計算できます。
0x7fffffff >>> 16 === 0x7fff;
-0x7fffffff >>> 16 === 0x8000;
0x80000001 >>> 16 === 0x8000;
(Math.floor( 0x7fffffff / 0x00010000) & 0xffff) === 0x7fff;
(Math.floor(-0x7fffffff / 0x00010000) & 0xffff) === 0x8000;
(Math.floor( 0x80000001 / 0x00010000) & 0xffff) === 0x8000;
2. BigInt
型の場合
JavaScript では BigInt
型を用いることで大きな数を扱えますが、Number
型より計算に時間がかかります。
/**
* BigInt をビッグエンディアン形式で Uint8Array に変換する
*/
const bigIntToUint8ArrayInBigEndian = bigInt => {
const uint8Array = new Uint8Array(8);
uint8Array[0] = Number(bigInt >> 56n & 0xffn);
uint8Array[1] = Number(bigInt >> 48n & 0xffn);
uint8Array[2] = Number(bigInt >> 40n & 0xffn);
uint8Array[3] = Number(bigInt >> 32n & 0xffn);
uint8Array[4] = Number(bigInt >> 24n & 0xffn);
uint8Array[5] = Number(bigInt >> 16n & 0xffn);
uint8Array[6] = Number(bigInt >> 8n & 0xffn);
uint8Array[7] = Number(bigInt & 0xffn);
return uint8Array;
};
例
// 長さが 64 ビットの正の整数
const bigIntA = 0x12345678_9abcdef0n;
console.log(bigIntA.toString(16));
const uint8ArrayA = bigIntToUint8ArrayInBigEndian(bigIntA);
console.log(Array.from(uint8ArrayA, uint8 => uint8.toString(16).padStart(2, '0')).join());
// 長さが 64 ビットの正の整数
const bigIntB = 0x7fffffff_ffffffffn;
console.log(bigIntB.toString(16));
const uint8ArrayB = bigIntToUint8ArrayInBigEndian(bigIntB);
console.log(Array.from(uint8ArrayB, uint8 => uint8.toString(16).padStart(2, '0')).join());
// 長さが 64 ビットの負の整数
const bigIntC = -0x7fffffff_ffffffffn;
console.log(bigIntC.toString(16));
const uint8ArrayC = bigIntToUint8ArrayInBigEndian(bigIntC);
console.log(Array.from(uint8ArrayC, uint8 => uint8.toString(16).padStart(2, '0')).join());
例の実行結果
123456789abcdef0
12,34,56,78,9a,bc,de,f0
7fffffffffffffff
7f,ff,ff,ff,ff,ff,ff,ff
-7fffffffffffffff
80,00,00,00,00,00,00,01