我正在执行按位运算,其结果显然被存储为二进制补码。当我将鼠标悬停在变量上时,它会存储在num = -2086528968.
我想要的那个数字的二进制是-(10000011101000100001100000111000)
。
但是当我说num.toString(2)
时,我得到了完全不同的二进制表示形式,即原始数字的二进制形式而不是2s comp(-1111100010111011111110011111001000)。
如何退回第一个字符串?
链接到转换器:rapidtables.com/convert/number/decimal-to-binary.html输入这个号码:-2086528968
以下显示结果:
var number = -2086528968;
var bin = (number >>> 0).toString(2)
//10000011101000100001100000111000
console.log(bin)
pedro已经回答了这个问题,但是由于这是黑客行为,而且不完全直观,我将对其进行解释。
我正在执行按位运算,其结果显然被存储为二进制补码。将鼠标悬停在变量上时,会看到
num = -2086528968
否,大多数位运算的结果是32位signed整数。这意味着位0x80000000
被解释为符号,后跟31位值。
奇怪的位序列是由于JS如何对值进行字符串化,例如sign + Math.abs(value).toString(base)
;
如何处理?我们需要告诉JS not将该位解释为符号,但作为值的一部分。但是如何?
一个易于理解的解决方案是将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”。您还记得我说过most位操作返回一个int32
吗?实际上有一个操作返回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);
仅在数字为负数或始终为负数时才运行此移位代码吗?
通常来说,在正整数上运行nr >>> 0
并没有什么害处,但请注意不要过度使用它。
技术上,JS仅支持数字,即double
值([64bit floating point
值)] >>。引擎内部还使用int32
值;在可能的情况。但没有uint32
值。因此,当您将负数int32
转换为uint32
时,引擎会将其转换为double
。而且,如果您再进行一次位操作,则它要做的第一件事就是将其转换回去。
因此,可以在需要实际的uint32
值时进行此操作,例如在此处打印位,但是应该避免在两次操作之间进行这种转换。就像“只是修复它”。