整体思路:

  1. 在数据流中从左向右读取每一个二进制数据
  2. 记录前缀连零的个数\(m\),遇到1停止记录。并提取后缀信息位(信息位长度与前缀0个数相同)
  3. 将后缀二进制转换成十进制数\(k\)
  4. 解码数值:\(decodeNum = 2^m – 1 + k\)
  5. 重复步骤1-4,直到数据序列结束

新建一个VS工程,定义数据类型:

  1. typedef unsigned char UINT8;

定义一个数组用来存储待解码的数据:

  1. UINT8 strArray[6] = { 0xA6, 0x43, 0x98, 0xE2, 0x04, 0x8A };

需要三个参数:待解码数据序列buf,解码到第几个字节bytePosition,第几位bitPosition (都是从左向右数的,每个字节自第一位bitPosition=0,最后一位bitPosition=7)

  1. static int get_bit_at_position(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
  2. {
  3. UINT8 mask = 0, val = 0;
  4. // mask用来表示提取第几位的数据,eg:0001 0000,表示提取第5位的数据
  5. mask = 1 << (7 - bitPosition);
  6. // 将当前字节数据与mask进行按位与运算,只保留那一位上的数据,整体数据!=0表明那一位数据为1
  7. // val保存bytePosition上,第bitPosition的值
  8. val = ((buf[bytePosition] & mask) != 0);
  9. // 如果读到字节末尾,修改两个Position的值
  10. if (++bitPosition > 7)
  11. {
  12. bytePosition++;
  13. bitPosition = 0;
  14. }
  15. return val;
  16. }

参照公式:\(decodeNum = 2^m – 1 + k\)\(m\)为前面0的个数,\(k\)为后缀二进制对应十进制的值

  1. static int get_uev_code_num(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
  2. {
  3. assert(bitPosition < 8);
  4. UINT8 val = 0, prefixZeroCount = 0; //存储每一位的数值; 前缀0的个数
  5. int prefix = 0, surfix = 0, decodeNum = 0;
  6. //统计前缀0的个数
  7. while (true)
  8. {
  9. val = get_bit_at_position(buf, bytePosition, bitPosition);
  10. if (val == 0)
  11. {
  12. prefixZeroCount++;
  13. }
  14. else
  15. {
  16. break;
  17. }
  18. }
  19. // 表示计算公式中 2^m - 1 部分
  20. prefix = (1 << prefixZeroCount) - 1;
  21. // 计算后缀中二进制转十进制部分 k
  22. for (size_t i = 0; i < prefixZeroCount; i++)
  23. {
  24. val = get_bit_at_position(buf, bytePosition, bitPosition);
  25. surfix += val*(1 << (prefixZeroCount - i - 1));
  26. }
  27. decodeNum = prefix + surfix;
  28. return decodeNum;
  29. }
  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. UINT8 strArray[6] = { 0xA6, 0x43, 0x98, 0xE2, 0x04, 0x8A };
  4. UINT8 bytePosition = 0, bitPosition = 0;
  5. // 保存bit数据长度
  6. UINT8 dataLengthInBits = sizeof(strArray) * 8;
  7. // 保存解码后的数据
  8. int decodeNum = 0;
  9. while ((bytePosition * 8 + bitPosition) < dataLengthInBits)
  10. {
  11. decodeNum = get_uev_code_num(strArray, bytePosition, bitPosition);
  12. printf("ExpColumb codeNum = %d\n", decodeNum);
  13. }
  14. return 0;
  15. }

运行结果如下:
1 解码结果

定义待编码数组,及编码后存储的数组:

  1. UINT8 oriNumArray[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 带编码数组
  2. UINT8 encodeArray[6] = { 0 }; // 存储指数哥伦布编码后的结果

整体思路:
以codeNum = 13为例,
① 前缀0的个数:\(prefixLen = floor[log_2(codeNum+1)] = 3\)
② 中间添加一个 1
③ 后缀部分的二进制:\(codeNum+1-2^{prefixLen} = 14-8 = 6 = b(1 1 0)\)
因此13的指数哥伦布编码码字为0 0 0 1 1 1 0。

与解码部分相同,使用了bytePosition和bitPosition表示写入位置。
【使用按位或的方式,按位写入每一位数据】
例如:该写某一字节code的第五位,这一个字节为 1101 0000,要在第五位上写入1(0同理),
创建一个mask -> 0000 1000,将code这个字节与mask进行按位或运算,即可将1写入到第五位上
code | mask = 1101 1000

  1. static void encode_uev_array(UINT8 *encodeArray, UINT8 codeNum, UINT8 &bytePosition, UINT8 &bitPosition)
  2. {
  3. // 前缀0
  4. int preZeroLen = floor(log(codeNum + 1) / log(2));
  5. bitPosition = bitPosition + preZeroLen;
  6. if (bitPosition > 7)
  7. {
  8. bytePosition++;
  9. bitPosition = bitPosition % 8;
  10. }
  11. // 中间1
  12. UINT8 mask = 1 << (7 - bitPosition);
  13. encodeArray[bytePosition] = encodeArray[bytePosition] | mask;
  14. if (++bitPosition > 7)
  15. {
  16. bytePosition++;
  17. bitPosition = 0;
  18. }
  19. // 后缀二进制
  20. int surDecNum = codeNum + 1 - pow(2, preZeroLen);
  21. dec_to_bin(encodeArray, surDecNum, bytePosition, bitPosition, preZeroLen);
  22. }
  1. static void dec_to_bin(UINT8 *encodeArray, UINT8 decNum, UINT8 &bytePosition, UINT8 &bitPosition, int preZeroLen)
  2. {
  3. if (preZeroLen == 0)
  4. {
  5. return;
  6. }
  7. // 转换二进制用的mask
  8. UINT8 maskBin = 1 << (preZeroLen - 1);
  9. // 按位写数据用的mask
  10. UINT8 maskVal;
  11. UINT8 val = 0;
  12. // 写入二进制后缀
  13. for (size_t i = 0; i < preZeroLen; i++)
  14. {
  15. val = (decNum & maskBin ? 1 : 0);
  16. maskVal = val << (7 - bitPosition);
  17. encodeArray[bytePosition] = encodeArray[bytePosition] | maskVal;
  18. if (++bitPosition > 7)
  19. {
  20. bytePosition++;
  21. bitPosition = 0;
  22. }
  23. maskBin = maskBin >> 1;
  24. }
  25. }
  1. UINT8 encodeArray[6] = { 0 };
  2. UINT8 bytePosition = 0, bitPosition = 0;
  3. UINT8 oriNumArray[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  4. UINT8 oriNumLen = sizeof(oriNumArray) / sizeof(UINT8);
  5. for (size_t i = 0; i < oriNumLen; i++)
  6. {
  7. encode_uev_array(encodeArray, oriNumArray[i], bytePosition, bitPosition);
  8. printf("%d \n", bitPosition);*/
  9. }
  10. for (size_t k = 0; k < 6; k++)
  11. {
  12. printf("%x ", encodeArray[k]);
  13. }

运行结果如下,与第一部分中待解码数组中数据相同,证明编解码部分程序能正确执行。
2

版权声明:本文为shuofxz原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/shuofxz/p/8528803.html