mirror of
				https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
				synced 2025-11-04 07:15:21 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			274 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @name CeL Hamming function
 | 
						|
 * @fileoverview 本檔案包含了 Hamming Code, 漢明碼的 functions。
 | 
						|
 * @since 2010/3/21 14:26:08
 | 
						|
 * @example <code>
 | 
						|
	CeL.run('data.math.Hamming');
 | 
						|
	var hc = CeL.Hamming.encode('1100');
 | 
						|
 | 
						|
 
 | 
						|
	TODO:
 | 
						|
	最佳化
 | 
						|
	calculate generator matrix
 | 
						|
	SEC-DED ("single error correction, double error detection") 版本(加在最後)
 | 
						|
	http://www.ee.unb.ca/cgi-bin/tervo/hamming.pl
 | 
						|
	最小漢明距離3
 | 
						|
	http://phpbb.godfat.org/viewtopic.php?t=66&sid=6e34dd040aa98c64c75bfe099008c82a
 | 
						|
	BCH碼
 | 
						|
 | 
						|
 </code>
 | 
						|
 */
 | 
						|
 | 
						|
// More examples: see /_test suite/test.js
 | 
						|
'use strict';
 | 
						|
// 'use asm';
 | 
						|
 | 
						|
// --------------------------------------------------------------------------------------------
 | 
						|
 | 
						|
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
 | 
						|
typeof CeL === 'function' && CeL.run({
 | 
						|
	// module name
 | 
						|
	name : 'data.math.Hamming',
 | 
						|
 | 
						|
	// require : '',
 | 
						|
 | 
						|
	// 設定不匯出的子函式。
 | 
						|
	no_extend : '*',
 | 
						|
 | 
						|
	// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
 | 
						|
	code : module_code
 | 
						|
});
 | 
						|
 | 
						|
function module_code(library_namespace) {
 | 
						|
 | 
						|
	// nothing required
 | 
						|
 | 
						|
	var module_name = this.id;
 | 
						|
 | 
						|
	// ============================================================================
 | 
						|
	// definition of module Hamming
 | 
						|
 | 
						|
	var
 | 
						|
	/**
 | 
						|
	 * Hamming code
 | 
						|
	 * 
 | 
						|
	 * @class Hamming Code 的 constructor
 | 
						|
	 * @constructor
 | 
						|
	 */
 | 
						|
	_// JSDT:_module_
 | 
						|
	= function() {
 | 
						|
		return this.encode.apply(this, arguments);
 | 
						|
	};
 | 
						|
 | 
						|
	// class public interface ---------------------------
 | 
						|
 | 
						|
	_// JSDT:_module_
 | 
						|
	.
 | 
						|
	/**
 | 
						|
	 * 是否左右顛倒。 default: data[1,2,..] 左至右, reverse: data[..,2,1] 右至左
 | 
						|
	 * 
 | 
						|
	 * @_memberOf _module_
 | 
						|
	 */
 | 
						|
	reverse = false;
 | 
						|
 | 
						|
	_// JSDT:_module_
 | 
						|
	.
 | 
						|
	/**
 | 
						|
	 * encode data to Hamming Code.
 | 
						|
	 * 
 | 
						|
	 * @param data
 | 
						|
	 *            data stream
 | 
						|
	 * @param no_reverse
 | 
						|
	 *            forced NO reverse
 | 
						|
	 * @return {String} encoded Hamming Code
 | 
						|
	 * @_memberOf _module_
 | 
						|
	 */
 | 
						|
	encode = function(data, no_reverse) {
 | 
						|
		data = (Array.isArray(data) ? data.join('') : '' + data).replace(
 | 
						|
				/[ ,]/g, '');
 | 
						|
		if (!/^[01]{1,20}$/.test(data))
 | 
						|
			return '';
 | 
						|
		if (this.reverse && !no_reverse)
 | 
						|
			data = data.split('').reverse().join('');
 | 
						|
		if (false)
 | 
						|
			library_namespace.debug('encode [' + d + ']', 1, module_name
 | 
						|
					+ '.encode');
 | 
						|
		var g = [ '' ], i_g = 1, bin = 1, i, i_d = 0, l_d = data.length, ch;
 | 
						|
		for (;; i_g++) {
 | 
						|
			if (i_g === bin) {
 | 
						|
				if (false)
 | 
						|
					library_namespace.debug('initial [' + g.length + '] as 0',
 | 
						|
							1, module_name + '.encode');
 | 
						|
				g.push(0);
 | 
						|
				bin *= 2;
 | 
						|
			} else {
 | 
						|
				if (false)
 | 
						|
					library_namespace.debug('initial [' + g.length + '] as '
 | 
						|
							+ d.charAt(i_d) + ' (' + i_d + '/' + l_d + ')', 1,
 | 
						|
							module_name + '.encode');
 | 
						|
				g.push(ch = data.charAt(i_d));
 | 
						|
				for (i = 1; i < bin; i *= 2)
 | 
						|
					if (i_g & i)
 | 
						|
						g[i] ^= ch;
 | 
						|
				if (++i_d === l_d)
 | 
						|
					break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (library_namespace.is_debug(2)) {
 | 
						|
			// for debug print
 | 
						|
			for (bin = i = 1, i_d = []; i < g.length; i++) {
 | 
						|
				ch = g[i];
 | 
						|
				if (i === bin)
 | 
						|
					ch = '<span style="color: #292;">' + ch + '</span>',
 | 
						|
							bin *= 2;
 | 
						|
				// i_d 在這表示一個專門用於顯示的 array
 | 
						|
				i_d.push(ch);
 | 
						|
			}
 | 
						|
			library_namespace.log('Hamming code of [' + data + ']: ['
 | 
						|
					+ i_d.join('') + ']');
 | 
						|
		}
 | 
						|
 | 
						|
		if (this.reverse && !no_reverse)
 | 
						|
			g = g.reverse();
 | 
						|
		return g.join('');
 | 
						|
	};
 | 
						|
 | 
						|
	_// JSDT:_module_
 | 
						|
	.
 | 
						|
	/**
 | 
						|
	 * 將 Hamming Code 分成 data & check bits
 | 
						|
	 * 
 | 
						|
	 * @param code
 | 
						|
	 *            Hamming Code to split
 | 
						|
	 * @return [資料位元 data bits, 檢查位元 check bits (parity bits)]
 | 
						|
	 * @_memberOf _module_
 | 
						|
	 */
 | 
						|
	split_code = function(code) {
 | 
						|
		if (Array.isArray(code))
 | 
						|
			code = code.join('');
 | 
						|
		code = (' ' + code).split('');
 | 
						|
		library_namespace.debug('split [' + code + ']', 1, module_name
 | 
						|
				+ '.split_code', 3);
 | 
						|
		var i = 1, l = code.length, cb = [];
 | 
						|
		while (i < l) {
 | 
						|
			cb.push(code[i]);
 | 
						|
			code[i] = '';
 | 
						|
			i *= 2;
 | 
						|
		}
 | 
						|
		library_namespace.debug('→ data [' + code.join('').replace(/ +/g, '')
 | 
						|
				+ '], check bits  [' + cb + ']', 1,
 | 
						|
				module_name + '.split_code', 3);
 | 
						|
		return [ code.join('').replace(/ +/g, ''), cb ];
 | 
						|
	};
 | 
						|
 | 
						|
	_// JSDT:_module_
 | 
						|
	.
 | 
						|
	/**
 | 
						|
	 * decode Hamming Code to data
 | 
						|
	 * 
 | 
						|
	 * @param code
 | 
						|
	 * @return
 | 
						|
	 * @_memberOf _module_
 | 
						|
	 */
 | 
						|
	decode = function(code) {
 | 
						|
		if (!code
 | 
						|
				|| !/^[01]{3,30}$/
 | 
						|
						.test(code = ('' + code).replace(/[ ,]/g, '')))
 | 
						|
			return '';
 | 
						|
		code = code.split('');
 | 
						|
		if (this.reverse)
 | 
						|
			code = code.reverse();
 | 
						|
 | 
						|
		var i = 0, l = code.length, ch, bin = 1, split_c = this
 | 
						|
				.split_code(code), test_c, cb;
 | 
						|
 | 
						|
		if (!split_c)
 | 
						|
			return;
 | 
						|
		// check bits (parity bits)
 | 
						|
		cb = split_c[1];
 | 
						|
		test_c = this.encode(split_c[0], 1);
 | 
						|
		if (!test_c || !(test_c = this.split_code(test_c)))
 | 
						|
			return;
 | 
						|
 | 
						|
		library_namespace.debug('received check bits: [' + cb.join('')
 | 
						|
				+ '], calculated: [' + test_c[1].join('') + ']', 1, module_name
 | 
						|
				+ '.decode');
 | 
						|
		test_c = parseInt(test_c[1].reverse().join(''), 2)
 | 
						|
				^ parseInt(cb.reverse().join(''), 2);
 | 
						|
		library_namespace.debug('error bit'
 | 
						|
				+ (this.reverse ? ' (do reversed XOR)' : '') + ': ' + test_c
 | 
						|
				+ '(' + test_c.toString(2) + '), ' + code.join(''), 1,
 | 
						|
				module_name + '.decode');
 | 
						|
		if (test_c)
 | 
						|
			if (test_c < code.length) {
 | 
						|
				code[test_c - 1] ^= 1;
 | 
						|
				split_c = this.split_code(code);
 | 
						|
			} else {
 | 
						|
				// 這算是能檢測出 2 bits 以上錯誤的特殊例子,機率通常也不大:已經超過 index 了。
 | 
						|
				// e.g., reversed 011010001100
 | 
						|
				library_namespace.debug(
 | 
						|
						'<em>Out of index!</em> More than 2 errors occurred.',
 | 
						|
						1, module_name + '.decode');
 | 
						|
			}
 | 
						|
 | 
						|
		if (library_namespace.is_debug())
 | 
						|
			if (test_c) {
 | 
						|
				cb = code.join('\0').split('\0');
 | 
						|
				cb[test_c - 1] = '<span style="color:#f33;">' + cb[test_c - 1]
 | 
						|
						+ '</span>';
 | 
						|
				library_namespace.debug('→ ' + cb.join(''), 1, module_name
 | 
						|
						+ '.decode');
 | 
						|
			} else
 | 
						|
				library_namespace.debug('The Hamming code is correct.', 1,
 | 
						|
						module_name + '.decode');
 | 
						|
 | 
						|
		split_c = split_c[0];
 | 
						|
		if (this.reverse)
 | 
						|
			split_c = split_c.split('').reverse().join('');
 | 
						|
		return split_c;
 | 
						|
	};
 | 
						|
 | 
						|
	_// JSDT:_module_
 | 
						|
	.
 | 
						|
	/**
 | 
						|
	 * 顯示 Hamming Code 的計算方法
 | 
						|
	 * 
 | 
						|
	 * @param {Number}
 | 
						|
	 *            bit_length bit length. e.g., 8, 16.
 | 
						|
	 * @_memberOf _module_
 | 
						|
	 */
 | 
						|
	show = function(bit_length) {
 | 
						|
		var code = [], bit = [], parity = [], i = 1, j, k, d = 1, a = 1, cc = 1, dc = 1;
 | 
						|
		for (;; i++) {
 | 
						|
			bit[i] = i.toString(2);
 | 
						|
			if (i === a) {
 | 
						|
				code[i] = 'C' + Math.pow(2, cc++ - 1);
 | 
						|
				a *= 2;
 | 
						|
			} else {
 | 
						|
				code[i] = 'D' + dc++;
 | 
						|
				for (j = 1, k = 1; j < cc; j++, k *= 2)
 | 
						|
					if (i & k)
 | 
						|
						if (parity[j])
 | 
						|
							parity[j] += '<span style="color:#aaa;">⊕</span>'
 | 
						|
									+ code[i];
 | 
						|
						else
 | 
						|
							parity[j] = code[i];
 | 
						|
				if (dc > bit_length)
 | 
						|
					break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		for (i = 1; i < code.length; i++) {
 | 
						|
			a = code[i];
 | 
						|
			if (j = a.match(/^C(\d+)$/))
 | 
						|
				a += ' = '
 | 
						|
						+ parity[Math.round(Math.log(j[1]) * Math.LOG2E) + 1];
 | 
						|
			library_namespace.debug(bit[i] + ': ' + a);
 | 
						|
		}
 | 
						|
 | 
						|
	};
 | 
						|
 | 
						|
	return (_// JSDT:_module_
 | 
						|
	);
 | 
						|
}
 |