【问题标题】:JavaScript BigInt print unsigned binary represenationJavaScript BigInt 打印无符号二进制表示
【发布时间】:2022-01-14 12:28:49
【问题描述】:

使用 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

【问题讨论】:

  • 要解决 TypeError,您还需要将 0 包装在 BigInt 中。但是 BigInt 没有无符号右移,因为 BigInt 没有确定的长度。
  • 对,对不起,但这给出了另一个错误消息。我已经更新了我的答案。
  • 由于负 BigInts 表示为无限长的二进制补码,因此您无法将它们转换为二进制 - 您需要将它们转换为固定长度的值(如数字)或编写将转换它们的自定义函数基于当前长度。
  • 明白这似乎是合乎逻辑的。所以我知道我的数字总是 64 位无符号整数,那我该怎么做呢?
  • 由于 JS 数字是 64 位双精度数,您可能需要编写一个自定义类来基于 BigInt 来处理它。您还可以编写一个函数,将 BigInt 数转换为二进制表示,将每个 BigInt 视为 64 位值。

标签: javascript bit-manipulation bit-shift bigint


【解决方案1】:

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

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

请注意:

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

BigInt 有类似 bitAtIndex 的东西吗?

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


@Kyroath:

负 BigInts 表示为无限长的二进制补码

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

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

【讨论】:

  • 感谢您的解决方案和解释!
【解决方案2】:

这是一种将 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

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

【讨论】:

  • 非常感谢!
猜你喜欢
  • 2019-08-12
  • 1970-01-01
  • 2012-01-13
  • 2013-11-18
  • 1970-01-01
  • 2018-04-29
  • 2023-03-03
  • 2016-03-19
  • 2013-08-22
相关资源
最近更新 更多