最近正好公司有个项目需要将现有编码转为汉明码进行数据传输,闲来无事,就简单写了一个demo实现汉明码的输出和校验。
汉明码(Hamming Code)是广泛用于内存和磁盘纠错的编码。汉明码不仅可以用来检测转移数据时发生的错误,还可以用来修正错误。(要注意的是,汉明码只能发现和修正一位错误,对于两位或者两位以上的错误无法正确和发现)。
Demo实现的是12位原始二进制数范围(即十进制数据范围在0~4096之间),此时需要使用5位汉明校验码进行校验,一共为17位。
其中汉明校验码分别位于第1,2,4,8,16位。
P16 | P8 | P4 | P2 | P1 | |
D3 | 0 | 0 | 0 | 1 | 1 |
D5 | 0 | 0 | 1 | 0 | 1 |
D6 | 0 | 0 | 1 | 1 | 0 |
D7 | 0 | 0 | 1 | 1 | 1 |
D9 | 0 | 1 | 0 | 0 | 1 |
D10 | 0 | 1 | 0 | 1 | 0 |
D11 | 0 | 1 | 0 | 1 | 1 |
D12 | 0 | 1 | 1 | 0 | 0 |
D13 | 0 | 1 | 1 | 0 | 1 |
D14 | 0 | 1 | 1 | 1 | 0 |
D15 | 0 | 1 | 1 | 1 | 1 |
D17 | 1 | 0 | 0 | 0 | 1 |
根据上表,可以得出:
1 2 3 4 5 6 |
P1 = D3 ^ D5 ^ D7 ^ D9 ^ D11 ^ D13 ^ D15 ^ D17 P2 = D3 ^ D6 ^ D7 ^ D10 ^ D11 ^ D14 ^ D15 P4 = D5 ^ D6 ^ D7 ^ D12 ^ D13 ^ D14 ^ D15 P8 = D9 ^ D10 ^ D11 ^ D12 ^ D13 ^ D14 ^ D15 P16 = D17 (^:表示异或) |
汉明码生成
汉明码输出——将十进制数字输入函数中,返回生成的汉明码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def hanming(code): code = bin(int(code)) code = str(code)[2:] # 判断待验证位数是否达到12位,不足位数前面补0 while len(code) < 12: code = '0' + code code_list = list(code) code_1 = int(code_list[0]) ^ int(code_list[1]) ^ int(code_list[3]) ^ int(code_list[4]) ^ int(code_list[6]) ^ int(code_list[8]) ^ int(code_list[10]) ^ int(code_list[11]) code_2 = int(code_list[0]) ^ int(code_list[2]) ^ int(code_list[3]) ^ int(code_list[5]) ^ int(code_list[6]) ^ int(code_list[9]) ^ int(code_list[10]) code_4 = int(code_list[1]) ^ int(code_list[2]) ^ int(code_list[3]) ^ int(code_list[7]) ^ int(code_list[8]) ^ int(code_list[9]) ^ int(code_list[10]) code_8 = int(code_list[4]) ^ int(code_list[5]) ^ int(code_list[6]) ^ int(code_list[7]) ^ int(code_list[8]) ^ int(code_list[9]) ^ int(code_list[10]) code_16 = int(code_list[11]) code_list.insert(0, str(code_1)) code_list.insert(1, str(code_2)) code_list.insert(3, str(code_4)) code_list.insert(7, str(code_8)) code_list.insert(15, str(code_16)) hanming_code = ''.join(code_list) return hanming_code |
汉明码校验
汉明码校验时同样根据生成的表格,将汉明校验码得出。不同的时,校验时需要将自身一起加入进行校验,即:
1 2 3 4 5 |
P1 = D1 ^ D3 ^ D5 ^ D7 ^ D9 ^ D11 ^ D13 ^ D15 ^ D17 P2 = D2 ^ D3 ^ D6 ^ D7 ^ D10 ^ D11 ^ D14 ^ D15 P4 = D4 ^ D5 ^ D6 ^ D7 ^ D12 ^ D13 ^ D14 ^ D15 P8 = D8 ^ D9 ^ D10 ^ D11 ^ D12 ^ D13 ^ D14 ^ D15 P16 = D16 ^ D17 |
然后按P16,P8,P4,P2,P1的顺序将二进制数拼接起来,得出汉明码的错误位数。将错误位数修成再剔除汉明校验码,即可还原为原始数据。
汉明码校验——将汉明码输入函数,返回二进制原始数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
def check_hanming(hanming_code): hanming_str = str(hanming_code) # 判断待验证数据长度是否为17位,不足位数前面补0 while len(hanming_str) < 17: hanming_str = '0'+hanming_str code_list = list(str(hanming_str)) code_1 = int(code_list[0]) ^ int(code_list[2]) ^ int(code_list[4]) ^ int(code_list[6]) ^ int(code_list[8]) ^ int(code_list[10]) ^ int(code_list[12]) ^ int(code_list[14]) ^ int(code_list[16]) code_2 = int(code_list[1]) ^ int(code_list[2]) ^ int(code_list[5]) ^ int(code_list[6]) ^ int(code_list[9]) ^ int(code_list[10]) ^ int(code_list[13]) ^ int(code_list[14]) code_4 = int(code_list[3]) ^ int(code_list[4]) ^ int(code_list[5]) ^ int(code_list[6]) ^ int(code_list[11]) ^ int(code_list[12]) ^ int(code_list[13]) ^ int(code_list[14]) code_8 = int(code_list[7]) ^ int(code_list[8]) ^ int(code_list[9]) ^ int(code_list[10]) ^ int(code_list[11]) ^ int(code_list[12]) ^ int(code_list[13]) ^ int(code_list[14]) code_16 = int(code_list[15]) ^ int(code_list[16]) checksum_list = [str(code_16), str(code_8), str(code_4), str(code_2), str(code_1)] # 确认错误的位数 code_checksum = int(''.join(checksum_list), 2) print('checksum={}'.format(code_checksum)) # 修改对应位数的数据 try: if code_checksum != 0: if code_list[code_checksum-1] == '0': code_list[code_checksum-1] = '1' else: code_list[code_checksum-1] = '0' except Exception as e: if e == 'list index out of range': print(e) code = code_list[2] + code_list[4] + code_list[5] + code_list[6] + code_list[8] + code_list[9] + code_list[10]\ + code_list[11] + code_list[12] + code_list[13] + code_list[14] + code_list[16] return int(code, 2) |
输出结果:
1 2 |
请输入待编码数据(0~4095):20 已生成汉明码:01000000000101000 |
1 2 3 4 |
请输入待验证汉明码:01000000000101001 # 故意输错最后一位 待验证汉明码:01000000000101001 checksum=17 已还原数据码:20 |