将二进制补码数转换为其二进制表示

Converting a Two's complement number to its binary representation

我正在执行按位运算,其结果显然存储为二进制补码。当我将鼠标悬停在它存储的变量上时,我看到 - num = -2086528968.

我想要的那个数字的二进制是 - (10000011101000100001100000111000)

但是当我说 num.toString(2) 我得到一个完全不同的二进制表示,原始数字的二进制而不是 2s comp(-1111100010111011110011111001000).

如何取回第一个字符串?

Link 到转换器:rapidtables.com/convert/number/decimal-to-binary.html 输入这个数字:-2086528968

按照下面的结果:

var number = -2086528968;
    
    var bin = (number >>> 0).toString(2)
    //10000011101000100001100000111000
    console.log(bin)

pedro 已经回答了这个问题,但由于这是一个 hack,并不完全直观,我将对其进行解释。

I am performing bitwise operations, the result of which is apparently being stored as a two's complement number. When I hover over the variable its stored in I see num = -2086528968

不,大多数位运算的结果是 32 位 有符号 整数。这意味着位 0x80000000 被解释为一个符号后跟 31 位值。

奇怪的位序列是因为 JS 如何将值字符串化,类似于 sign + Math.abs(value).toString(base);

如何处理?我们需要告诉 JS 而不是 将该位解释为符号,而是作为值的一部分。但是怎么办?

一个易于理解的解决方案是将 0x100000000 添加到负数,从而得到它们的正数对应部分。

function print(value) {
  if (value < 0) {
    value += 0x100000000;
  }
  console.log(value.toString(2).padStart(32, 0));
}

print(-2086528968);

另一种方法是分别转换低位和高位

function print(value) {
  var signBit = value < 0 ? "1" : "0";
  var valueBits = (value & 0x7FFFFFFF).toString(2);

  console.log(signBit + valueBits.padStart(31, 0));
}

print(-2086528968);


//or lower and upper half of the bits:
function print2(value) {
  var upperHalf = (value >> 16 & 0xFFFF).toString(2);
  var lowerHalf = (value & 0xFFFF).toString(2);
  console.log(upperHalf.padStart(16, 0) + lowerHalf.padStart(16, 0));
}

print2(-2086528968);

另一种方式涉及 pedro 使用的 "hack"。您还记得我是怎么说 大多数 位运算 return 和 int32 的吗?有一种操作实际上 return 是一个 unsigned (32bit) 整数,即所谓的 Zero-fill right shift.

所以number >>> 0不会改变数字的位,但第一位不再解释为符号。

function uint32(value){
  return value>>>0;
}

function print(value){
  console.log(uint32(value).toString(2).padStart(32, 0));
}

print(-2086528968);

will I run this shifting code only when the number is negative, or always?

一般来说,运行 nr >>> 0 超过正整数没有坏处,但注意不要过大。

从技术上讲,JS 仅支持数字,即 double 个值 64bit floating point 个值)。引擎内部也使用 int32 值;在可能的情况。但是没有 uint32 值。因此,当您将负 int32 转换为 uint32 时,引擎会将其转换为 double。如果你跟进另一个位操作,它所做的第一件事就是将它转换回来。

所以当你需要一个实际的 uint32 值时这样做很好,比如在这里打印位,但你应该避免操作之间的这种转换。喜欢 "just to fix it".