假设我有一个最大的32位整数-
const a =
((2 ** 32) - 1)
const b =
parseInt("11111111111111111111111111111111", 2) // 32 bits, each is a one!
console.log(a === b) // true
console.log(a.toString(2))
// 11111111111111111111111111111111 (32 ones)
console.log(b.toString(2))
// 11111111111111111111111111111111 (32 ones)
到目前为止,一切都很好。但是,现在让我们说我想使用八(8)个4位数字制作一个32位数字。这个想法很简单:将每个4位序列移(<<
)到位置,然后将它们相加(+
)-
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) + make (more, e + 4)
const print = n =>
console.log(n.toString(2))
// 4 bits
print(make([ 15 ])) // 1111
// 8 bits
print(make([ 15, 15 ])) // 11111111
// 12 bits
print(make([ 15, 15, 15 ])) // 111111111111
// 16 bits
print(make([ 15, 15, 15, 15 ])) // 1111111111111111
// 20 bits
print(make([ 15, 15, 15, 15, 15 ])) // 11111111111111111111
// 24 bits
print(make([ 15, 15, 15, 15, 15, 15 ])) // 111111111111111111111111
// 28 bits
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111
// almost there ... now 32 bits
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
我得到-1
,但预期结果是所有结果的32位或11111111111111111111111111111111
。
更糟的是,如果我从预期的结果开始并且往后走,我会得到预期的结果-
const c =
`11111111111111111111111111111111`
const d =
parseInt(c, 2)
console.log(d) // 4294967295
console.log(d.toString(2) === c) // true
我尝试调试我的make函数以确保没有明显的问题-
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? `0`
: `(${bit} << ${e}) + ` + make (more, e + 4)
console.log(make([ 15, 15, 15, 15, 15, 15, 15, 15 ]))
// (15 << 0) + (15 << 4) + (15 << 8) + (15 << 12) + (15 << 16) + (15 << 20) + (15 << 24) + (15 << 28) + 0
该公式看起来像签出。我以为可能与+
有关,并切换到按位或(|
),它应该在这里有效地做同样的事情-
const a =
parseInt("1111",2)
const b =
(a << 0) | (a << 4)
console.log(b.toString(2)) // 11111111
const c =
b | (a << 8)
console.log(c.toString(2)) // 111111111111
但是,尝试合并全部八(8)个数字时,我的make
函数遇到相同的错误-
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) | make (more, e + 4)
const print = n =>
console.log(n.toString(2))
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111 (28 bits)
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
有什么作用?
目标是使用JavaScript将八(8)个4位整数转换为单个32位整数-这只是我的尝试。我很好奇我的功能在哪里中断,但我愿意接受其他解决方案。
我想避免将每个4位整数转换为二进制字符串,将二进制字符串混在一起,然后将二进制字符串解析为单个int。首选数字解决方案。
答案 0 :(得分:13)
按位运算符将产生一个 signed 32位数字,这意味着,如果位置31处的位(从右边的最低有效位开始计数,即位0)为1,则数字将为负。
为避免发生这种情况,请使用<<
或|
以外的其他运算符,这两个运算符都会产生一个带符号的32位数字。例如:
(bit * 2**e) + make (more, e + 4)
移位运算符旨在将结果强制进入有符号的32位范围,至少在mdn(在撰写本文时)中声明:
所有按位运算符的操作数都转换为带符号的32位整数
实际上这并非完全正确。 >>>
运算符是一个例外。 EcmaScript 2015, section 12.5.8.1声明操作数在移入0位之前已映射到 unsigned 32位。因此,即使您将零位移位,也会看到这种效果。
您只需要将其应用于最终值一次,例如在您的print
函数中:
console.log((n>>>0).toString(2))
如果您需要的位数甚至超过32位,并且您的JavaScript引擎已经支持BigInt,就像some一样,请对按位运算符所涉及的操作数使用BigInts-然后,这些将 不使用32位带符号的数字换行(注意后缀n
):
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
注意:如果在执行上述操作时遇到错误,请使用Chrome重试...