总体思路:数组
新建一个VS工程,定义数据类型:函数
typedef unsigned char UINT8;
定义一个数组用来存储待解码的数据:编码
UINT8 strArray[6] = { 0xA6, 0x43, 0x98, 0xE2, 0x04, 0x8A };
须要三个参数:待解码数据序列buf,解码到第几个字节bytePosition,第几位bitPosition (都是从左向右数的,每一个字节自第一位bitPosition=0,最后一位bitPosition=7)spa
static int get_bit_at_position(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition) { UINT8 mask = 0, val = 0; // mask用来表示提取第几位的数据,eg:0001 0000,表示提取第5位的数据 mask = 1 << (7 - bitPosition); // 将当前字节数据与mask进行按位与运算,只保留那一位上的数据,总体数据!=0代表那一位数据为1 // val保存bytePosition上,第bitPosition的值 val = ((buf[bytePosition] & mask) != 0); // 若是读到字节末尾,修改两个Position的值 if (++bitPosition > 7) { bytePosition++; bitPosition = 0; } return val; }
参照公式:$decodeNum = 2^m - 1 + k$,$m$为前面0的个数,$k$为后缀二进制对应十进制的值code
static int get_uev_code_num(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition) { assert(bitPosition < 8); UINT8 val = 0, prefixZeroCount = 0; //存储每一位的数值; 前缀0的个数 int prefix = 0, surfix = 0, decodeNum = 0; //统计前缀0的个数 while (true) { val = get_bit_at_position(buf, bytePosition, bitPosition); if (val == 0) { prefixZeroCount++; } else { break; } } // 表示计算公式中 2^m - 1 部分 prefix = (1 << prefixZeroCount) - 1; // 计算后缀中二进制转十进制部分 k for (size_t i = 0; i < prefixZeroCount; i++) { val = get_bit_at_position(buf, bytePosition, bitPosition); surfix += val*(1 << (prefixZeroCount - i - 1)); } decodeNum = prefix + surfix; return decodeNum; }
int _tmain(int argc, _TCHAR* argv[]) { UINT8 strArray[6] = { 0xA6, 0x43, 0x98, 0xE2, 0x04, 0x8A }; UINT8 bytePosition = 0, bitPosition = 0; // 保存bit数据长度 UINT8 dataLengthInBits = sizeof(strArray) * 8; // 保存解码后的数据 int decodeNum = 0; while ((bytePosition * 8 + bitPosition) < dataLengthInBits) { decodeNum = get_uev_code_num(strArray, bytePosition, bitPosition); printf("ExpColumb codeNum = %d\n", decodeNum); } return 0; }
运行结果以下: get
定义待编码数组,及编码后存储的数组:it
UINT8 oriNumArray[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 带编码数组 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。io
与解码部分相同,使用了bytePosition和bitPosition表示写入位置。 【使用按位或的方式,按位写入每一位数据】 例如:该写某一字节code的第五位,这一个字节为 1101 0000,要在第五位上写入1(0同理), 建立一个mask -> 0000 1000,将code这个字节与mask进行按位或运算,便可将1写入到第五位上 code | mask = 1101 1000class
static void encode_uev_array(UINT8 *encodeArray, UINT8 codeNum, UINT8 &bytePosition, UINT8 &bitPosition) { // 前缀0 int preZeroLen = floor(log(codeNum + 1) / log(2)); bitPosition = bitPosition + preZeroLen; if (bitPosition > 7) { bytePosition++; bitPosition = bitPosition % 8; } // 中间1 UINT8 mask = 1 << (7 - bitPosition); encodeArray[bytePosition] = encodeArray[bytePosition] | mask; if (++bitPosition > 7) { bytePosition++; bitPosition = 0; } // 后缀二进制 int surDecNum = codeNum + 1 - pow(2, preZeroLen); dec_to_bin(encodeArray, surDecNum, bytePosition, bitPosition, preZeroLen); }
static void dec_to_bin(UINT8 *encodeArray, UINT8 decNum, UINT8 &bytePosition, UINT8 &bitPosition, int preZeroLen) { if (preZeroLen == 0) { return; } // 转换二进制用的mask UINT8 maskBin = 1 << (preZeroLen - 1); // 按位写数据用的mask UINT8 maskVal; UINT8 val = 0; // 写入二进制后缀 for (size_t i = 0; i < preZeroLen; i++) { val = (decNum & maskBin ? 1 : 0); maskVal = val << (7 - bitPosition); encodeArray[bytePosition] = encodeArray[bytePosition] | maskVal; if (++bitPosition > 7) { bytePosition++; bitPosition = 0; } maskBin = maskBin >> 1; } }
UINT8 encodeArray[6] = { 0 }; UINT8 bytePosition = 0, bitPosition = 0; UINT8 oriNumArray[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; UINT8 oriNumLen = sizeof(oriNumArray) / sizeof(UINT8); for (size_t i = 0; i < oriNumLen; i++) { encode_uev_array(encodeArray, oriNumArray[i], bytePosition, bitPosition); printf("%d \n", bitPosition);*/ } for (size_t k = 0; k < 6; k++) { printf("%x ", encodeArray[k]); }
运行结果以下,与第一部分中待解码数组中数据相同,证实编解码部分程序能正确执行。 数据类型