如何从八 (8) 个 4 位整数创建 32 位整数?
How to create a 32-bit integer from eight (8) 4-bit integers?
假设我有一个最大 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。首选数值解决方案。
按位运算符将产生一个 signed 32 位数,这意味着如果位置 31 的位(从右边的最低有效位开始计算,即位 0 ) 为 1,则数为负数。
为避免这种情况发生,请使用除 <<
或 |
之外的其他运算符,它们都会生成带符号的 32 位数字。例如:
(bit * 2**e) + make (more, e + 4)
强制 无符号 32 位
位移运算符旨在将结果强制到带符号的 32 位范围内,至少在 mdn(撰写本文时)上声称如此:
The operands of all bitwise operators are converted to signed 32-bit integers
这其实不完全正确。 >>>
运算符是一个例外。 EcmaScript 2015, section 12.5.8.1 声明操作数在移入 0 位之前映射到 unsigned 32 位。因此,即使您将 零 位移动,您也会看到这种效果。
您只需将它应用于最终值一次,例如在您的 print
函数中:
console.log((n>>>0).toString(2))
BigInt 解决方案
如果您需要超过 32 位,并且您的 JavaScript 引擎支持 BigInt like some 已经支持,那么将 BigInts 用于位运算符中涉及的操作数——这些将 not 使用 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...
再试一次
假设我有一个最大 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。首选数值解决方案。
按位运算符将产生一个 signed 32 位数,这意味着如果位置 31 的位(从右边的最低有效位开始计算,即位 0 ) 为 1,则数为负数。
为避免这种情况发生,请使用除 <<
或 |
之外的其他运算符,它们都会生成带符号的 32 位数字。例如:
(bit * 2**e) + make (more, e + 4)
强制 无符号 32 位
位移运算符旨在将结果强制到带符号的 32 位范围内,至少在 mdn(撰写本文时)上声称如此:
The operands of all bitwise operators are converted to signed 32-bit integers
这其实不完全正确。 >>>
运算符是一个例外。 EcmaScript 2015, section 12.5.8.1 声明操作数在移入 0 位之前映射到 unsigned 32 位。因此,即使您将 零 位移动,您也会看到这种效果。
您只需将它应用于最终值一次,例如在您的 print
函数中:
console.log((n>>>0).toString(2))
BigInt 解决方案
如果您需要超过 32 位,并且您的 JavaScript 引擎支持 BigInt like some 已经支持,那么将 BigInts 用于位运算符中涉及的操作数——这些将 not 使用 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...
再试一次