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