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 26 /** 27 * 本 module 之 name(id),<span style="text-decoration:line-through;">不設定時會從呼叫時之 path 取得</span>。 28 * @type String 29 * @constant 30 * @inner 31 * @ignore 32 */ 33 var module_name = 'math.Hamming'; 34 35 //=================================================== 36 /** 37 * 若欲 include 整個 module 時,需囊括之 code。 38 * @type Function 39 * @param {Function} library_namespace namespace of library 40 * @param load_arguments 呼叫時之 argument(s) 41 * @return 42 * @name CeL.math.Hamming 43 * @constant 44 * @inner 45 * @ignore 46 */ 47 var code_for_including = function(library_namespace, load_arguments) { 48 49 50 51 //============================================================================ 52 // definition of module Hamming 53 54 var 55 /** 56 * Hamming code 57 * @class Hamming Code 的 constructor 58 * @constructor 59 */ 60 CeL.math.Hamming 61 = function() { 62 return this.encode.apply(this, arguments); 63 }; 64 65 //class public interface --------------------------- 66 67 CeL.math.Hamming 68 . 69 /** 70 * 是否左右顛倒。 71 * default: data[1,2,..] 左至右, reverse: data[..,2,1] 右至左 72 * @memberOf CeL.math.Hamming 73 */ 74 reverse = false; 75 76 77 CeL.math.Hamming 78 . 79 /** 80 * encode data to Hamming Code. 81 * @param data data stream 82 * @param no_reverse forced NO reverse 83 * @return {String} encoded Hamming Code 84 * @memberOf CeL.math.Hamming 85 */ 86 encode = function(data, no_reverse) { 87 data = (library_namespace.is_Array(data) ? data.join('') : '' + data) 88 .replace(/[ ,]/g, ''); 89 if (!/^[01]{1,20}$/.test(data)) 90 return ''; 91 if (this.reverse && !no_reverse) 92 data = data.split('').reverse().join(''); 93 // library_namespace.debug('encode [' + d + ']',1,module_name + '.encode'); 94 var g = [ '' ], i_g = 1, bin = 1, i, i_d = 0, l_d = data.length, ch; 95 for (;; i_g++) { 96 if (i_g === bin) 97 // library_namespace.debug('initial [' + g.length + '] as 0',1,module_name + '.encode'), 98 g.push(0), bin *= 2; 99 else { 100 // library_namespace.debug('initial [' + g.length + '] as ' + d.charAt(i_d) + ' (' + i_d + '/' + l_d + ')',1,module_name + '.encode'); 101 g.push(ch = data.charAt(i_d)); 102 for (i = 1; i < bin; i *= 2) 103 if (i_g & i) 104 g[i] ^= ch; 105 if (++i_d === l_d) 106 break; 107 } 108 } 109 110 111 if (library_namespace.is_debug()) { 112 // for debug print 113 for (bin = i = 1, i_d = []; i < g.length; i++) { 114 ch = g[i]; 115 if (i === bin) 116 ch = '<span style="color:#292;">' + ch + '</span>', bin *= 2; 117 // i_d 在這表示一個專門用於顯示的 array 118 i_d.push(ch); 119 } 120 library_namespace.log('Hamming code of [' + data + ']: [' 121 + i_d.join('') + ']'); 122 } 123 124 if (this.reverse && !no_reverse) 125 g = g.reverse(); 126 return g.join(''); 127 }; 128 129 130 CeL.math.Hamming 131 . 132 /** 133 * 將 Hamming Code 分成 data & check bits 134 * @param code Hamming Code to split 135 * @return [資料位元 data bits, 檢查位元 check bits (parity bits)] 136 * @memberOf CeL.math.Hamming 137 */ 138 split_code = function(code) { 139 if (library_namespace.is_Array(code)) 140 code = code.join(''); 141 code = (' ' + code).split(''); 142 library_namespace.debug('split [' + code + ']', 1, module_name + '.split_code'); 143 var i = 1, l = code.length, cb = []; 144 while (i < l) 145 cb.push(code[i]), code[i] = '', i *= 2; 146 library_namespace.debug('→ data [' + code.join('').replace(/ +/g, '') + '], check bits [' + cb + ']', 1, module_name + '.split_code'); 147 return [ code.join('').replace(/ +/g, ''), cb ]; 148 }; 149 150 CeL.math.Hamming 151 . 152 /** 153 * decode Hamming Code to data 154 * @param code 155 * @return 156 * @memberOf CeL.math.Hamming 157 */ 158 decode = function(code) { 159 if (!code || !/^[01]{3,30}$/.test(code = ('' + code).replace(/[ ,]/g, ''))) 160 return ''; 161 code = code.split(''); 162 if (this.reverse) 163 code = code.reverse(); 164 165 var i = 0, l = code.length, ch, bin = 1, split_c = this.split_code(code), test_c, cb; 166 167 if (!split_c) 168 return; 169 // check bits (parity bits) 170 cb = split_c[1]; 171 test_c = this.encode(split_c[0], 1); 172 if (!test_c || !(test_c = this.split_code(test_c))) 173 return; 174 175 library_namespace.debug('received check bits: [' + cb.join('') + '], calculated: [' + test_c[1].join('') + ']', 1, module_name + '.decode'); 176 test_c = parseInt(test_c[1].reverse().join(''), 2) 177 ^ parseInt(cb.reverse().join(''), 2); 178 library_namespace.debug('error bit' + (this.reverse ? ' (do reversed XOR)' : '') + ': ' + test_c + '(' + test_c.toString(2) + '), ' + code.join(''), 1, module_name + '.decode'); 179 if (test_c) 180 if (test_c < code.length) 181 code[test_c - 1] ^= 1, split_c = this.split_code(code); 182 else 183 // 這算是能檢測出 2 bits 以上錯誤的特殊例子,機率通常也不大:已經超過 index 了。 184 // e.g., reversed 011010001100 185 library_namespace.debug('<em>Out of index!</em> More than 2 errors occurred.', 1, module_name + '.decode'); 186 187 if (library_namespace.is_debug()) 188 if (test_c) { 189 cb = code.join('\0').split('\0'); 190 cb[test_c - 1] = '<span style="color:#f33;">' + cb[test_c - 1] + '</span>'; 191 library_namespace.debug('→ ' + cb.join(''), 1, module_name + '.decode'); 192 } else 193 library_namespace.debug('The Hamming code is correct.', 1, module_name + '.decode'); 194 195 split_c = split_c[0]; 196 if (this.reverse) 197 split_c = split_c.split('').reverse().join(''); 198 return split_c; 199 }; 200 201 202 CeL.math.Hamming 203 . 204 /** 205 * 顯示 Hamming Code 的計算方法 206 * @param {Number} bit_length bit length. e.g., 8, 16. 207 * @memberOf CeL.math.Hamming 208 */ 209 show = function(bit_length) { 210 var code = [], bit = [], parity = [], i = 1, j, k, d = 1, a = 1, cc = 1, dc = 1; 211 for (;; i++) { 212 bit[i] = i.toString(2); 213 if (i === a) 214 code[i] = 'C' + Math.pow(2, cc++ - 1), a *= 2; 215 else { 216 code[i] = 'D' + dc++; 217 for (j = 1, k = 1; j < cc; j++, k *= 2) 218 if (i & k) 219 if (parity[j]) 220 parity[j] += '<span style="color:#aaa;">⊕</span>' + code[i]; 221 else 222 parity[j] = code[i]; 223 if (dc > bit_length) 224 break; 225 } 226 } 227 for (i = 1; i < code.length; i++) { 228 a = code[i]; 229 if (j = a.match(/^C(\d+)$/)) 230 a += ' = ' + parity[Math.round(Math.log(j[1]) * Math.LOG2E) + 1]; 231 library_namespace.debug(bit[i] + ': ' + a); 232 } 233 234 }; 235 236 237 /** 238 * 不 extend 的 member 239 * @ignore 240 */ 241 CeL.math.Hamming 242 .no_extend = '*'; 243 244 245 return ( 246 CeL.math.Hamming 247 ); 248 }; 249 250 //============================================================================ 251 252 CeL.setup_module(module_name, code_for_including); 253 254 }; 255