JavaScript BigInt 打印无符号二进制表示

JavaScript BigInt print unsigned binary represenation

使用 JavaScript 的 BigInt 时如何打印无符号整数?

BigInts 可以使用 toString(2) 打印为二进制表示。但是,对于负值,此函数仅在打印时附加一个 - 符号。

BigInt(42).toString(2)
// output => 101010
BigInt(-42).toString(2)
// output => -101010

如何打印 BigInt(42) 的无符号表示?我认为使用常规 numbers 你可以做 (-42 >>> 0).toString(2),但是 BigInt 似乎没有实现无符号右移,导致错误

(BigInt(-42) >>> BigInt(0)).toString(2)
// TypeError: BigInts have no unsigned right shift, use >> instead

下面是将 64 位 BigInts 转换为二进制字符串的方法:

// take two's complement of a binary string
const twosComplement = (binaryString) => {
  let complement = BigInt('0b' + binaryString.split('').map(e => e === "0" ? "1" : "0").join(''));
  return decToBinary(complement + BigInt(1));
}

const decToBinary = (num) => {
  let result = ""

  const isNegative = num < 0;
  if (isNegative) num = -num;

  while (num > 0) {
    result = (num % BigInt(2)) + result;
    num /= BigInt(2);
  }

  if (result.length > 64) result = result.substring(result.length - 64);
  result = result.padStart(64, "0");

  if (isNegative) result = twosComplement(result);
  return result;
}

console.log(decToBinary(BigInt(5))); // 0000000000000000000000000000000000000000000000000000000000000101
console.log(decToBinary(BigInt(-5))); // 1111111111111111111111111111111111111111111111111111111111111011

但是,此代码不进行任何验证。

获取负 BigInt 的二进制补码表示的一种简单方法是使用 BigInt.asUintN(bit_width, bigint):

> BigInt.asUintN(64, -42n).toString(2)
'1111111111111111111111111111111111111111111111111111111111010110'

注意:

  • 您必须定义所需的位数(在我的示例中为 64),对此没有“自然”/自动值。
  • 仅给定该二进制数字串,无法判断这是一个正 BigInt(值接近 2n**64n)还是 -42n 的二进制补码表示。因此,如果您想稍后反转转换,则必须以某种方式提供此信息(例如,通过编写代码使其隐含地假定一个或另一个选项)。
  • 相关地,这不是 -42n 在当前浏览器中的内部存储方式。 (但这并不需要您担心,因为您可以随时 want/need 创建此输出。)
  • 您可以通过减法获得相同的结果:((2n ** 64n) - 42n).toString(2) -- 同样,您可以指定要查看的位数。

Is there something like bitAtIndex for BigInt?

不,因为没有关于如何表示 BigInt 的规范。引擎可以选择以他们想要的任何方式使用位,只要生成的 BigInts 的行为符合规范要求。


@Kyroath:

negative BigInts are represented as infinite-length two's complement

不,它们不是:当前浏览器中的实现将 BigInts 表示为“符号 + 大小”,而不是二进制补码。然而,这是一个无法观察到的实现细节:实现可能会改变它们在内部存储 BigInts 的方式,而 BigInts 的行为将完全相同。

您可能想说的是,任何负整数(大或小)的二进制补码表示在概念上都是无限的 1 位流,因此在有限 space 中打印或存储它总是需要定义一些 characters/bits 之后流被简单地切断。当你有一个固定宽度的类型时,这显然定义了这个分界点;对于概念上无限的 BigInts,您必须自己定义它。