1 2 /** 3 * @name CeL Hamming function 4 * @fileoverview 5 * 本檔案包含了 Hamming Code, 漢明碼的 functions。 6 * @since 2010/3/21 14:26:08 7 * @example 8 * CeL.use('math.Hamming'); 9 * var hc = CeL.Hamming.encode('1100'); 10 */ 11 12 13 /* 14 TODO: 15 最佳化 16 calculate generator matrix 17 SEC-DED ("single error correction, double error detection") 版本(加在最後) 18 http://www.ee.unb.ca/cgi-bin/tervo/hamming.pl 19 最小漢明距離3 20 http://phpbb.godfat.org/viewtopic.php?t=66&sid=6e34dd040aa98c64c75bfe099008c82a 21 BCH碼 22 */ 23 24 if (typeof CeL === 'function') 25 CeL.setup_module('data.math.Hamming', 26 function(library_namespace, load_arguments) { 27 28 // nothing required 29 30 31 var module_name = this.module_name; 32 33 34 //============================================================================ 35 // definition of module Hamming 36 37 var 38 /** 39 * Hamming code 40 * @class Hamming Code 的 constructor 41 * @constructor 42 */ 43 CeL.data.math.Hamming 44 = function() { 45 return this.encode.apply(this, arguments); 46 }; 47 48 //class public interface --------------------------- 49 50 CeL.data.math.Hamming 51 . 52 /** 53 * 是否左右顛倒。 54 * default: data[1,2,..] 左至右, reverse: data[..,2,1] 右至左 55 * @memberOf CeL.data.math.Hamming 56 */ 57 reverse = false; 58 59 60 CeL.data.math.Hamming 61 . 62 /** 63 * encode data to Hamming Code. 64 * @param data data stream 65 * @param no_reverse forced NO reverse 66 * @return {String} encoded Hamming Code 67 * @memberOf CeL.data.math.Hamming 68 */ 69 encode = function(data, no_reverse) { 70 data = (library_namespace.is_Array(data) ? data.join('') : '' + data) 71 .replace(/[ ,]/g, ''); 72 if (!/^[01]{1,20}$/.test(data)) 73 return ''; 74 if (this.reverse && !no_reverse) 75 data = data.split('').reverse().join(''); 76 // library_namespace.debug('encode [' + d + ']',1,module_name + '.encode'); 77 var g = [ '' ], i_g = 1, bin = 1, i, i_d = 0, l_d = data.length, ch; 78 for (;; i_g++) { 79 if (i_g === bin) 80 // library_namespace.debug('initial [' + g.length + '] as 0', 1, module_name + '.encode'), 81 g.push(0), bin *= 2; 82 else { 83 // library_namespace.debug('initial [' + g.length + '] as ' + d.charAt(i_d) + ' (' + i_d + '/' + l_d + ')', 1, module_name + '.encode'); 84 g.push(ch = data.charAt(i_d)); 85 for (i = 1; i < bin; i *= 2) 86 if (i_g & i) 87 g[i] ^= ch; 88 if (++i_d === l_d) 89 break; 90 } 91 } 92 93 94 if (library_namespace.is_debug()) { 95 // for debug print 96 for (bin = i = 1, i_d = []; i < g.length; i++) { 97 ch = g[i]; 98 if (i === bin) 99 ch = '<span style="color:#292;">' + ch + '</span>', bin *= 2; 100 // i_d 在這表示一個專門用於顯示的 array 101 i_d.push(ch); 102 } 103 library_namespace.log('Hamming code of [' + data + ']: [' 104 + i_d.join('') + ']'); 105 } 106 107 if (this.reverse && !no_reverse) 108 g = g.reverse(); 109 return g.join(''); 110 }; 111 112 113 CeL.data.math.Hamming 114 . 115 /** 116 * 將 Hamming Code 分成 data & check bits 117 * @param code Hamming Code to split 118 * @return [資料位元 data bits, 檢查位元 check bits (parity bits)] 119 * @memberOf CeL.data.math.Hamming 120 */ 121 split_code = function(code) { 122 if (library_namespace.is_Array(code)) 123 code = code.join(''); 124 code = (' ' + code).split(''); 125 library_namespace.debug('split [' + code + ']', 1, module_name + '.split_code'); 126 var i = 1, l = code.length, cb = []; 127 while (i < l) 128 cb.push(code[i]), code[i] = '', i *= 2; 129 library_namespace.debug('→ data [' + code.join('').replace(/ +/g, '') + '], check bits [' + cb + ']', 1, module_name + '.split_code'); 130 return [ code.join('').replace(/ +/g, ''), cb ]; 131 }; 132 133 CeL.data.math.Hamming 134 . 135 /** 136 * decode Hamming Code to data 137 * @param code 138 * @return 139 * @memberOf CeL.data.math.Hamming 140 */ 141 decode = function(code) { 142 if (!code || !/^[01]{3,30}$/.test(code = ('' + code).replace(/[ ,]/g, ''))) 143 return ''; 144 code = code.split(''); 145 if (this.reverse) 146 code = code.reverse(); 147 148 var i = 0, l = code.length, ch, bin = 1, split_c = this.split_code(code), test_c, cb; 149 150 if (!split_c) 151 return; 152 // check bits (parity bits) 153 cb = split_c[1]; 154 test_c = this.encode(split_c[0], 1); 155 if (!test_c || !(test_c = this.split_code(test_c))) 156 return; 157 158 library_namespace.debug('received check bits: [' + cb.join('') + '], calculated: [' + test_c[1].join('') + ']', 1, module_name + '.decode'); 159 test_c = parseInt(test_c[1].reverse().join(''), 2) 160 ^ parseInt(cb.reverse().join(''), 2); 161 library_namespace.debug('error bit' + (this.reverse ? ' (do reversed XOR)' : '') + ': ' + test_c + '(' + test_c.toString(2) + '), ' + code.join(''), 1, module_name + '.decode'); 162 if (test_c) 163 if (test_c < code.length) 164 code[test_c - 1] ^= 1, split_c = this.split_code(code); 165 else 166 // 這算是能檢測出 2 bits 以上錯誤的特殊例子,機率通常也不大:已經超過 index 了。 167 // e.g., reversed 011010001100 168 library_namespace.debug('<em>Out of index!</em> More than 2 errors occurred.', 1, module_name + '.decode'); 169 170 if (library_namespace.is_debug()) 171 if (test_c) { 172 cb = code.join('\0').split('\0'); 173 cb[test_c - 1] = '<span style="color:#f33;">' + cb[test_c - 1] + '</span>'; 174 library_namespace.debug('→ ' + cb.join(''), 1, module_name + '.decode'); 175 } else 176 library_namespace.debug('The Hamming code is correct.', 1, module_name + '.decode'); 177 178 split_c = split_c[0]; 179 if (this.reverse) 180 split_c = split_c.split('').reverse().join(''); 181 return split_c; 182 }; 183 184 185 CeL.data.math.Hamming 186 . 187 /** 188 * 顯示 Hamming Code 的計算方法 189 * @param {Number} bit_length bit length. e.g., 8, 16. 190 * @memberOf CeL.data.math.Hamming 191 */ 192 show = function(bit_length) { 193 var code = [], bit = [], parity = [], i = 1, j, k, d = 1, a = 1, cc = 1, dc = 1; 194 for (;; i++) { 195 bit[i] = i.toString(2); 196 if (i === a) 197 code[i] = 'C' + Math.pow(2, cc++ - 1), a *= 2; 198 else { 199 code[i] = 'D' + dc++; 200 for (j = 1, k = 1; j < cc; j++, k *= 2) 201 if (i & k) 202 if (parity[j]) 203 parity[j] += '<span style="color:#aaa;">⊕</span>' + code[i]; 204 else 205 parity[j] = code[i]; 206 if (dc > bit_length) 207 break; 208 } 209 } 210 for (i = 1; i < code.length; i++) { 211 a = code[i]; 212 if (j = a.match(/^C(\d+)$/)) 213 a += ' = ' + parity[Math.round(Math.log(j[1]) * Math.LOG2E) + 1]; 214 library_namespace.debug(bit[i] + ': ' + a); 215 } 216 217 }; 218 219 220 /** 221 * 不 extend 的 member 222 * @ignore 223 */ 224 CeL.data.math.Hamming 225 .no_extend = '*'; 226 227 228 229 230 return ( 231 CeL.data.math.Hamming 232 ); 233 } 234 235 236 ); 237 238