How to convert a Javascript number to a Uint8Array?
Asked Answered
I

4

5

I have a Javascript integer (whose precision can go up to 2^53 - 1), and I am trying to send it over the wire using an ArrayBuffer. I suppose I could use BigInt64Array, but the browser support still seems relatively new with that.

I cannot use Int32Array (which was my original solution), because the precision for that is up to 2^32 - 1, whereas a Javascript integer can safely go up to 2^53 - 1. This is my problem.

Is there an easy way to simply turn any Javascript integer into a Uint8Array of length 8?

For example, I am looking for a function like this:

function numToUint8Array(num) {
  let arr = new Uint8Array(8);

  // fill arr values with that of num

  return arr;
}

let foo = numToUint8Array(9458239048);
let bar = uint8ArrayToNum(foo); // 9458239048

Does something like this exist in the standard library already? If not, is there a way to write something like this?

Incautious answered 2/6, 2022 at 12:6 Comment(3)
"Does something like this exist in the standard library already?" - the BigInt64Array you already mentioned. "Is there a way to write something like this?" - just repeatedly divide by 256 and write num % 256 as one byte into your Uint8Array. Make sure to decide on the endianness.Paleoecology
@Paleoecology Oh, okay. And what is the formula for converting it back? uint8ArrayToNum I'm trying to think through it but not sure if I have it right. Going to post an answer.Incautious
What are the elements of foo expected to be for your example?Gluten
I
6

@Bergi, is something like this what you had in mind?

function numToUint8Array(num) {
  let arr = new Uint8Array(8);

  for (let i = 0; i < 8; i++) {
    arr[i] = num % 256;
    num = Math.floor(num / 256);
  }

  return arr;
}

function uint8ArrayToNumV1(arr) {
  let num = 0;

  for (let i = 0; i < 8; i++) {
    num += Math.pow(256, i) * arr[i];
  }

  return num;
}

function uint8ArrayToNumV2(arr) {
  let num = 0;

  for (let i = 7; i >= 0; i--) {
    num = num * 256 + arr[i];
  }

  return num;
}

let foo = numToUint8Array(9458239048);
let bar = uint8ArrayToNumV1(foo); // 9458239048
let baz = uint8ArrayToNumV2(foo); // 9458239048

console.log(foo, bar, baz);
Incautious answered 2/6, 2022 at 12:44 Comment(2)
Yes, basically that, although I'd have used num = num * 256 + arr[i] (and reverse iteration) in uint8ArrayToNum, for better symmetry with numToUint8Array.Paleoecology
Cool. that's even better. Editing my answer to include that one as well. Thanks!Incautious
A
1

This is the solution I currently like to use

// BigInt to Uint8Array
myBigInt = 123456789n;
dv = new DataView(new ArrayBuffer(8), 0);
dv.setBigUint64(0, myBigInt);
uArr = new Uint8Array(dv.buffer);
console.debug('Uint8Array', uArr);

// Uint8Array to BigInt
bytesArr = new Uint8Array([0, 0, 0, 0, 7, 91, 205, 22]);
dv = new DataView(bytesArr.buffer, 0);
myBigInt = dv.getBigUint64();
console.debug('BigInt', myBigInt);
Antananarivo answered 4/6, 2024 at 8:15 Comment(1)
Note you sometimes might get an error "cannot convert <number> to a BigInt" (e.g. when trying to assign values larger than MAX_INT32 or MAX_UINT32). In that case try converting it to string first: dv.setBigUint64(0, myBigInt.toString()).Weeping
B
0

If you don't want to use Math class, you can use this script:

function numToUint8Array(num) {
  const arr = new Uint8Array(8);
  
  for(let i = 0; i < 8; i++)
    arr.set([num/0x100**i], 7-i)

  return arr;
}

function uint8ArrayToNum(arr) {
   let num = 0;
   
   for(let i = 0; i < 8; i++)
      num += (0x100**i) * arr[7-i];
   return num;
}

Test Code:

  const arr = numToUint8Array(257);
  console.log(arr);
  const num = uint8ArrayToNum(arr);
  console.log(num);

Result:

Uint8Array(8) [
  0, 0, 0, 0,
  0, 0, 1, 1
]
257
Bouffard answered 7/9, 2022 at 8:3 Comment(0)
I
0

One-liner for numToUint8Array:

let n = 9458239048;
let array = new Uint8Array(new BigUint64Array([BigInt(n)]).buffer);
console.log(array);
Ingenuous answered 7/6, 2024 at 13:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.