【问题标题】:How to create a 32-bit integer from eight (8) 4-bit integers?如何从八 (8) 个 4 位整数创建一个 32 位整数?
【发布时间】:2019-08-18 20:01:02
【问题描述】:

假设我有一个最大 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。首选数值解。

【问题讨论】:

  • 看起来 bitwise operators“数字 -21474836482147483647 是可以通过 32 位有符号数字表示的最小和最大整数。” 确实(15 &lt;&lt; 28) 超出了这个范围,但是 JavaScript 的 MAX_SAFE_INTEGER 最多支持 53 位。是否有一种安全可靠的方法可以对大于 32 位的数字使用位运算符?
  • 签名真的不能接受吗?毕竟它们是相同的位,只是解释略有不同

标签: javascript twos-complement base-conversion


【解决方案1】:

位运算符将产生一个 有符号 32 位数字,这意味着如果位置 31 的位(从右侧的最低有效位开始计数,即位 0)为 1,则数字将是负数。

为避免这种情况发生,请使用除&lt;&lt;| 之外的其他运算符,它们都会生成带符号的32 位数字。例如:

(bit * 2**e) + make (more, e + 4)

强制无符号 32位

移位运算符旨在将结果强制为带符号的 32 位范围,至少在 mdn 上声称(在撰写本文时):

所有位运算符的操作数都转换为有符号的 32 位整数

这实际上并不完全正确。 &gt;&gt;&gt; 运算符是一个例外。 EcmaScript 2015, section 12.5.8.1 声明操作数在移入 0 位之前映射到 unsigned 32 位。因此,即使您移动 0 位,您也会看到这种效果。

您只需将其应用于最终值一次,例如在您的 print 函数中:

console.log((n>>>0).toString(2))

BigInt 解决方案

如果您需要超过 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 重试...

【讨论】:

  • bit 在这里有点用词不当。您实际上可以将 4 位直接乘以那里的指数吗?通常,基本转换是使用bit0 * 2**0 + bit1 * 2**1 + bit2 * 2**2 + bit3 * 2**3 等完成的。我想我必须将 4 位段分解为单独的位,并将每个位乘以递增的指数.
  • 不用猜了,我试过了,效果很好。谢谢@trincot。我今天学到了一个有用的基础转换捷径!
  • 在今天之前,我从未觉得 JavaScript 的位运算符有“缺点”。期待一组在 64 位空间中工作的新按位运算符是否合理?
  • 这并不是真正的缺点,而是有意的。我在我的答案中添加了一个新部分,您可能会感兴趣。
  • 太好了。我不知道 BigInt 支持已经在这里了。新部分非常有意义。
猜你喜欢
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 2012-05-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多