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