【问题标题】:Encoding and decoding two integer values both 0-3 into one byte将 0-3 的两个整数值编码和解码为一个字节
【发布时间】:2019-10-24 08:34:25
【问题描述】:

我正在尝试编码两个值,一个可以是 0、1、2 或 3 的“运动方向”和一个也可以是 0、1、2 或 3 的“观察方向”

我知道可以将此信息存储到一个字节中

所以我在按位运算方面还是个新手,所以试图弄清楚这一点让我很难过。

我想拥有像

这样的功能
function encode(m, l) {
   // returns byte
}

function decode(byte) {
    // returns { m, l }
}

【问题讨论】:

  • 一个字节需要打包多少个值?您需要 2 位来以二进制形式存储从 0 到 3 的值。
  • 哦,对了..所以我想我什至不需要一个完整的字节。那我只需要4位。我只想将这两个数字 m 和 l 存储到位中
  • 那么,似乎有什么问题?如果您想要一个字节中的两个值,请为它们分配不同的位,以便检索其中一个具有and,其中您的编号为 1,在所有其他位置为 0。

标签: javascript binary bit-manipulation


【解决方案1】:

首先,Javascript 没有字节数据类型。它只有数字类型。 Javascript 不需要将结果存储在单个字节中,即使它适合一个字节。

您需要 2 位来存储数字 0、1、2 或 3。 另外两个位来存储另一个 0,1,2,3。第二个数字需要位移 2 位并添加到第一个数字。这与乘以 4 相同。所以...

function encode(m,l) {
    return m + l * 4;
}

function decode(byte) {
  var m = byte % 4;
  var l = (byte - m ) /4;
  return {m:m, l:l};
}

使用查找可能会更快。

 (0,0) <=> 0
 (1,0) <=> 1
 (2,0) <=> 2
 (3,0) <=> 3
 (0,1) <=> 4
 (1,1) <=> 5
 (2,1) <=> 6
 (3,1) <=> 7
 (0,2) <=> 8
 (1,2) <=> 9
 (2,2) <=> 10
 (3,2) <=> 11
 (0,3) <=> 12
 (1,3) <=> 13
 (2,3) <=> 14
 (3,3) <=> 15

【讨论】:

    【解决方案2】:

    您可以映射一个字节以将左四位分配给运动,将右四位分配给观察方向,然后移动一点来设置它。解码使用右移并以对数为底 2 来查看设置了哪个位。

    const encode = (movement, lookDir) =>
      // mmmmllll
      (1 << (movement + 4)) | (1 << lookDir)
    ;
    
    const decode = byte =>
      [Math.log2(byte >> 4), Math.log2(byte & 0xF)]
    ;
    
    for (let i = 0; i < 4; i++) {
      for (let j = 0; j < 4; j++) {
        const encoded = encode(i, j);
        const decoded = decode(encoded);
        console.log(`[${i},${j}] was encoded as: ${encoded} and decoded back to ${decoded}`);
      }
    }

    【讨论】:

      【解决方案3】:

      我正在尝试编码两个值,一个可以是 0、1、2 或 3 的“运动方向”和一个也可以是 0、1、2 或 3 的“观察方向”

      对此的概括是bit field。如果你用二进制计算你的范围,那么你如何组合你的值会变得更直观:

      (0).toString(2).padStart(8, 0); // = 00000000
      (1).toString(2).padStart(8, 0); // = 00000001
      (2).toString(2).padStart(8, 0); // = 00000010
      (3).toString(2).padStart(8, 0); // = 00000011
      

      您的范围使用两个较低的位,因此要按位方式对它们进行编码,您需要做的就是将您的值之一移动到左侧相邻的两个位,然后将两个值或在一起。即第一个变量使用位 0,1,第二个变量使用位 2,3。

      const encodeC = (a, b) => (a << 2) | b;
      

      要解码a,我们只需反转c 上的移位,因为b 被推离“单词”右侧的末尾,所以不需要更多:

      const decodeA = (c) => c >> 2;
      

      要解码b,我们需要从c“屏蔽”它,以便选择两个低位并排除所有其他位,我们使用0b11的AND(&amp;)来做到这一点(3) :

      const decodeB = (c) => c & 3;
      

      请注意,在上面的示例中,b 必须保证在 0-3 范围内,否则它将溢出到为a 保留的位中。另一方面,a 还剩下 28 个空闲位,因此它可能会更高。

      正如其他人提到的,在内存分配方面,JavaScript 中的所有数字都使用 64 位(双精度),在执行按位运算时,它们会临时转换为 32 位有符号整数。这意味着您永远不能为单个变量使用更少的内存,并且最多只能将一半的位 (32) 用于位域。

      这并没有在 JavaScript 中使用无效的位域,例如,如果您要进一步编码为字符或通过 AJAX 发送的东西,则更是如此。您可以使用 c.toString(36) (0-36) 或 String.charFromCode(c + 32) (0-95)。对于 4 位的使用,您只需要 0-15 的范围。

      ...如果你编码成 ASCII 字符,它真的会使用一个字节:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多