How to create a 32-bit integer from eight (8) 4-bit integers?
假设我有一个最大32位整数-
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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位数字。这个想法很简单:将(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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 2 3 4 5 6 7 8 9 | const c = `11111111111111111111111111111111` const d = parseInt(c, 2) console.log(d) // 4294967295 console.log(d.toString(2) === c) // true |
我试着调试make函数以确保没有明显的问题-
1 2 3 4 5 6 7 | 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 |
。
这个公式看起来像是检验出来的。我想这可能与
1 2 3 4 5 6 7 8 9 10 11 12 | 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)个数字时,我的
1 2 3 4 5 6 7 8 9 10 11 12 | 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。建议使用数值解决方案。
位运算符将产生有符号的32位数字,这意味着如果位置31处的位(从右边最低有效位(即位0)算起)为1,则该数字将为负数。
为了避免这种情况发生,请使用除
1 | (bit * 2**e) + make (more, e + 4) |
强制无符号32位
位移位运算符旨在强制结果进入有符号32位范围,至少在MDN上声明(写入时):
The operands of all bitwise operators are converted to signed 32-bit integers
号
事实上,这并不完全正确。
您只需对最终值应用一次,例如在您的
1 | console.log((n>>>0).toString(2)) |
号Bigint解决方案
如果您甚至需要超过32位,并且您的javascript引擎支持bigint,就像一些已经支持的那样,那么对位运算符中涉及的操作数使用bigints——然后这些操作数将不使用32位有符号数字包装(注意
1 2 3 4 5 6 7 8 9 10 11 12 | 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再试一次…