【问题标题】:Encoding/decoding decimal values in variable-bitwidth binary blocks在可变位宽二进制块中编码/解码十进制值
【发布时间】:2015-04-23 11:17:53
【问题描述】:

我正在尝试为我正在设计的联网个人项目中的协议构建一个可变位宽二进制编码器/解码器......而我愚蠢的大脑已经完全卡住了如何掌握可变位宽二进制编码/解码。我已经盯着同一个 ~18 SLOC 大约四天了,我仍然觉得完全超出了我的深度。我确实觉得我应该能够掌握这一点,但不幸的是,当我尝试跟踪不同的数字关系时,我的大脑会随机崩溃:(

理论上,我想做的事情非常简单。我声明了一个位宽列表,以及我想要存储在该位宽内的值,如下所示:

[10 bits]: 1013
[1  bit ]: 1
[2  bits]: 3
[19 bits]: 51209

考虑到位宽,这些值将逐渐排序为二进制字符串,如下所示:

               1 bit
               | 2 bits  
               | ||  
  /-10 bits--\ | \/ /------ 19 bits ------\  
  12345678  12 3 45 678  12345678  12345678  
  11111101  01 1 11 000  11001000  00001001  
  \----------/ | \/ \---------------------/
      1012     1  3          51209

上面粗体的比特流是我通过网络传输的:

11111101  253  FD
01111000  120  78
11001000  200  C8
00001001    9  09

在另一端,我将列表{10, 1, 2, 19}(顶部表示的位宽集)与我收到的字节序列进行映射,然后留下我想要传输的原始值集。

虽然这主要是一个一般的算法问题,并且任何特定语言的语义都可以说是无关紧要的,但我应该提到我正在为此使用 PHP - 我如此卡住的部分原因是我正在尝试找出如何避免诉诸字符串操作,PHP 似乎痴迷于鼓励人们偏爱正确的数字处理。然而,这个函数将(希望)以 2 到 3 位数 Mbps 的速度处理数据,我希望这些例程尽可能快。 (顺便说一句,我会使用另一种语言,但 PHP 是我最了解的语言>_>)

我确实了解二进制的基础知识,我应该强调我确实有一个工作编码器,我认为(它向后输出二进制数据) - 但我不知道我在这里做什么。我不是在问“我如何编写这个函数”,而是在问“我正在做的事情的结构机制是什么,我什至如何掌握它。”

我还应该指出,这个问题并不是一个伪装得很好的家庭作业。它适用于我正在设计的个人软件项目中的网络库组件,希望能教会我有关网络、事件处理和并发性的知识。希望我能掌握我需要实施的所有其他事情......哈哈

【问题讨论】:

  • 你能分享你的尝试吗?
  • 请添加您已经尝试过/尝试过的内容并显示您正在寻找的内容(尽可能具体地描述它)!

标签: php encoding bit-manipulation binary-data


【解决方案1】:

为了给你一个小的起点,这样的二进制解码器/编码器看起来像这里的一个例子:

那么现在这背后的概念是什么?

非常简单,我循环遍历您要发送的每个数据并将它们分成单个字节。举个例子:

data:    1013
bitMask:   10

所以我首先计算发送它需要多少字节。这将是 2 个字节 à 8 位/字节。

在所有准备和计算之后,可以直接逐字节逐位发送所有数据!因此,如果我们从上面举个例子,它看起来像这样:

data:    1013  -> 0000'0011 1111'0101
bitMask:   10

total amount of bytes: 2
1. byte = 1111'0101
2. byte = 0000'0011

因此,在发送数据(此处为浏览器中的输出)时,您正在反向显示数据!因为当您收到它时,您正在将它改回来并且您会得到正确的结果!

<?php

    class binaryCoder {

        /* Properties */
        public $data;  // <-- save/receive data into this property
        public $bitMask = [];
        private $byteCount = 0x00;

        /* Constructor */
        public function __construct() {


        }

        /* Methods */
        public function writeData(array $data, array $bitMask) {

            $this->data = $data;
            $this->bitMask = $bitMask;
            $this->byteCount = array_reduce($this->bitMask, function($byteCount, $bits){
                return $byteCount + ceil($bits/8);
            }, 0x00);


            foreach(array_combine($this->bitMask, $this->data) as $mask => $data) {
                for($byteCounter = 0; $byteCounter < ceil($mask/8); $byteCounter++) {
                    $this->writeByte($data >> ($byteCounter*8));
                }
            }

        }

        public function readData(array $bitMask) {
            $this->bitMask = $bitMask;
            $byte = 0x00;


            foreach($this->bitMask as $key => $mask) {
                $message[$key] = "";
                for($byteCounter = 0; $byteCounter < ceil($mask/8); $byteCounter++, $byte++) {
                    $message[$key] = sprintf("%08d", $this->readByte($byte*8)) . $message[$key];
                }
            }

            $message = array_map("bindec", $message);
            print_r($message);

        }

        private function writeByte($byte) {
            for($bitCount = 0; $bitCount < 8; $bitCount++) {
                $this->writeBit((bool)($byte & (1 << $bitCount)));
            }
        }

        private function readByte($bytePosition) {
            $byte = 0x00;

            for($bitCount = 0; $bitCount < 8; $bitCount++) {
                $byte |= (int)$this->readBit($bytePosition+$bitCount) << $bitCount;
            }
            return decbin($byte);
        }

        private function writeBit($bit) {
            echo ($bit?1:0);  // --> send/write data to dest. (Note it's reversed!)
        }

        private function readBit($bit) {
            return $this->data[$bit];
        }


    }


    /* Testing */
    $binaryTransmitter = new binaryCoder();
    $binaryTransmitter->writeData([1013, 1, 3, 51209], [10, 1, 2, 19]);
    $binaryTransmitter->data = "10101111110000001000000011000000100100000001001100000000";  //received data 
    $binaryTransmitter->readData([10, 1, 2, 19]);

?>

输出:

10101111110000001000000011000000100100000001001100000000 //note output here is reversed!
Array ( [0] => 1013 [1] => 1 [2] => 3 [3] => 51209 )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 2021-06-11
    相关资源
    最近更新 更多